Promise的含义
Promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理且更强大。
Promise对象具有以下两个特点:
- 对象的状态不受外界影响。Promise对象代表一个异步操作,有3中状态:Pending(进行中)、Fulfilled(已成功)和Rejected(已失败)。
- 一旦状态改变就不会再变,任何时候都可以得到这个结果。
Promise也有一些缺点:
- 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise内部抛出的错误不会反应奥外部。
- 当处于Pending状态时,无法得知目前进展到哪一个阶段(刚开始还是即将完成)。
基本用法
ES6规定,Promise对象是一个构造函数,用来生成Promise实例。
var promise = new Promise(function(resolve,reject) {
// ...some code
If( /*异步操作成功*/){
resolve(value);
}else{
reject(error);
}
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。这两个函数有JavaScript引擎提供,不需要自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”。reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”。
Promise.prototype.then()
Promise实例生成以后,可以用then方法分别指定Resolved状态和Rejected状态的回调函数。
promise.then(function(value){
//成功
},function(error){
//失败
});
then方法接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为成功时调用,是必填的。第二个是Promise对象的状态变为失败时调用,是选填的。
Promise.prototype.catch()
Promise.prototype.catch()方法是.then(null,rejection)的别名,用于发生失败时的回调函数。
如果异步操作抛出错误,状态就会变为Rejected,然后就会调用catch方法指定的回调函数处理这个错误。
promise.then( (val) => {......} )
.catch( error) => {......} );
//等价于:
promise.then( (val) => {......}, (error) => {......} )
另外,then方法指定的回调函数如果在运行中抛出错误,也会被catch方法捕获。
promise.then( (val) => {
trow new error(“此错误也会被catch捕获到”);
} ).catch(
(error) => {......}
);
catch方法返回的还是一个Promise对象,因此后面还可以接着条用then方法。
promise.then( (val) => {
......
} ).catch(
(error) => {......}
).then(
(value2) => { ...... }
);
如果后面的then方法里面报错,就与前面的catch无关了。
Promise.all()
Promise.all方法用于将多个Promise实例包装成一个新的Promise实例。
var p = Promise.all( [ p1, p2, p3] );
Promise.all方法接受一个数组作为参数(不一定是数组,但必须是具有Iterator接口,且返回的每个成员都是Promise实例),p1, p2, p3都是Promise对象的实例。
P的状态由p1、 p2、 p3决定,分为两种情况:
- 只有p1、 p2、 p3的状态都变成Fulfilled,p的状态才会变成Fulfilled,此时p1、 p2、 p3的返回值组成一个数组,传递给p的回调函数。
- 只要p1、 p2、 p3中有一个被Rejected,p的装填就变成Rejected,此时第一个被Rejected的实例返回值会传递给p的回调函数。
如果作为参数的Promise实例自身定义了catch方法,那么它被rejected时并不会触发Promise.all()的catch方法。如下面的例子:
const p1 = new Promise((resolve,reject) => {
resolve(‘hello’);
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve,reject) => {
throw new error(“报错了”);
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then( result => console.log(result ) )
.catch(e => console.log(“e”));
//[ ‘hello’, Error:报错了]
如果去掉p2的catch方法则会执行Promise.all的catch方法。
const p1 = new Promise((resolve,reject) => {
resolve(‘hello’);
})
.then(result => result);
const p2 = new Promise((resolve,reject) => {
throw new error(“报错了”);
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then( result => console.log(result ) )
.catch(e => console.log(“e”));
// Error:报错了
Promise.race()
Promise.all方法同样是将多个Promise实例包装成一个新的Promise实例。
var p = Promise.race( [ p1, p2, p3] );
与 Promise.all不同的是,只要p1、 p2、 p3中有一个率先改变状态,P的状态就跟着改变。
Promise.resolved()
将现有的对象转化为Promise对象。
Promise.resolve(‘foo’);
//等价于
new Promise(result => result(“foo”))
Promise.reject()
返回一个新的Promise实例,状态为Rejected。
var p = Promise.reject(“出错了”);
//等同于
var p = new Promise(( resolve, reject) => reject(“出错了”));
两个有用的附加方法
done()
无论Promise对象的回调链以then方法还是catch方法结束,只要最后一个方法抛出错误,都有可能无法捕捉到。因此done方法就派上了用场,它总处于回调链的尾端,保证任何可能抛出的错误都会被捕捉到。
asyncFunc()
.then()
.catch()
.then()
.done();
finally()
Finally方法用于指定不管Promise对象最后状态如何都会执行的操作。它与done方法的最大区别在于,它接受一个普通的回调函数作为参数,该函数不管则么样都必须执行。
asyncFunc()
.then()
.catch()
.finally();
应用
加载图片
const preloadImage = function (path) {
return new Promise(
(resolve, reject) => {
var img = new Image();
img.onload = () => resolve("成功");
img.onerror = () => reject("失败");
img.src = path;
}
).then(
value => {console.log(value) //异步加载成功则调用该方法
}).catch(
value => console.log(value) //异步加载失败则调用该方法
);