Promise对象: 它最大的作用就是解决了异步回调函数层层嵌套的问题。
//传统写法:
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) { // ... });
});
});
});
//Promises的写法:
(new Promise(step1))
.then(step2)
.then(step3)
.then(step4);
从上面代码可以看到,采用Promises接口后,程序变得非常清楚易读
什么是Promise:
promise对象,说白了,就是个代理,充当异步操作与回调函数之间的中介。简单的说就是:每一个异步任务会立刻返回一个Promise对象。Promises对象有一个then方法,允许指定回调函数,在异步任务完成后调用。
Promise接口:
Promise对象有三种状态:
1 异步操作"未完成"(pending)
2 异步操作"已完成" (resolved)
3 异步操作"失败" (rejected)
这三种状态的变化途径只有2种:
1 异步操作从"未完成"到"已完成"
2 异步操作从"未完成“到"失败"
所以Promise对象的最终结果只有两种:
1 异步操作成功 Promise对象传回一个值,状态变为resolved
2 异步操作失败 Promise对象抛出一个错误,状态变为rejected
Promise对象的生成
ES6提供了原生的Promise构造函数
var promise = new Promise(function (resolve, reject) {
if(/*异步操作成功*/){
resolve(value)
}else {
reject(error);
}
});
Promise构造函数接收一个函数作为参数(必须),该函数的两个参数分别是resolve和reject.它们是两个函数。 resolve函数的作用是,将Promise对象的状态从"未完成"变成"成功",并将异步操作的结果,作为参数传递出去。reject函数的作用是,将Promise对象的状态从"未完成"变成"失败",在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。Promise实例生成后,你可以在你想用的地方去调用then方法
Promise的方法
API-1: Promise.all(iterable)
Promise.all(iterable)方法会等iterable参数内的所有promise都被resolve后resolve, 或以第一个promise被reject的原因而reject。
API-2:Promise.race(iterable)
Promise.race(iterable)方法返回一个promise,这个promise在iterable中任意一个promise被解决或拒绝后,立刻以相同的解决值被解决或以相同的拒绝原因被拒绝
Promise的应用
先来看看Promise的兼容性:
如何做到兼容:
方法一:通过Polyfill 类库
jakearchibald/es6-promise:一个兼容 ES6 Promises 的Polyfill类库。 它基于 RSVP.js 这个兼容 Promises/A+ 的类库, 它只是 RSVP.js 的一个子集,只实现了Promises 规定的 API。
yahoo/ypromise: 这是一个独立版本的 YUI 的 Promise Polyfill,具有和 ES6 Promises 的兼容性。
getify/native-promise-only: 以作为ES6 Promises的polyfill为目的的类库 它严格按照ES6 Promises的规范设计,没有添加在规范中没有定义的功能。 如果运行环境有原生的Promise支持的话,则优先使用原生的Promise支持。
方法二:通过扩展类库
then/promise: a super set of ES6 Promises designed to have readable, performant code and to provide just the extensions that are absolutely necessary for using promises today.
petkaantonov/bluebird: 这个类库除了兼容 Promise 规范之外,还扩展了取消promise对象的运行,取得promise的运行进度,以及错误处理的扩展检测等非常丰富的功能,此外它在实现上还在性能问题下了很大的功夫。
when: 大小很小,node和浏览器环境下都可以使用。
q: 类库 Q 实现了 Promises 和 Deferreds 等规范。 它自2009年开始开发,还提供了面向Node.js的文件IO API Q-IO 等, 是一个在很多场景下都能用得到的类库。
接下来看两个简单的应用:
应用一:加载图片
我们可以把图片的加载写成一个Promise对象
var preloadImage = function (path) {
return new Promise(function (resolve, reject) {
var image = new Image();
image.onload = resolve;
image.onerror = reject;
image.src = path;
});
};
应用二:Ajax操作
function search(term, onload, onerror) {
var xhr, results, url;
url = 'http://example.com/search?q=' + term;
xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function (e) {
if (this.status === 200) {
results = JSON.parse(this.responseText);
onload(results);
}
};
xhr.onerror = function (e){
onerror(e);
};
xhr.send();
}
search("Hello World", console.log, console.error);
改写后
function search(term, onload, onerror) {
var url = 'http://example.com/search?q=' + term;
var xhr = new XMLHttpRequest();
var result;
var p = new Promise(function (resolve, reject) {
xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function (e) {
xhr.open('GET', url, true);
xhr.onload = function (e) {
if (this.status === 200) {
results = JSON.parse(this.responseText);
resolve(results);
};
}
xhr.onerror = function (e){
reject(e);
};
xhr.send();
});
return p;
}
search("Hello World", console.log, console.error);