主要知识点:Promise生命周期、Promise基本操做、Promise链、响应多个Promise以及集成Promise编程
什么是回调地狱?数组
当使用回调函数来进行事件处理的时候,若是嵌套多层回调函数的时候,就会出现回调地狱,例如:promise
method1(function(err, result) {
if (err) {
throw err;
}
method2(function(err, result) {
if (err) {
throw err;
}
method3(function(err, result) {
if (err) {
throw err;
}
method4(function(err, result) {
if (err) {
throw err;
}
method5(result);
});
});
});
});
复制代码
像本例同样嵌套多个方法调用会建立错综复杂的代码,会难以理解与调试。当想要实现更复 杂的功能时,回调函数也会存在问题。要是你想让两个异步操做并行运行,而且在它们都结 束后提醒你,那该怎么作?要是你想同时启动两个异步操做,但只采用首个结束的结果,那 又该怎么作?而使用Promise就能避免回调地狱的状况。异步
Promise能够当作是一个占位符,表示异步操做的执行结果。函数能够返回一个Promise,而没必要订阅一个事件或者向函数传递一个回调函数。异步编程
Promise的生命周期函数
每一个 Promise 都会经历一个短暂的生命周期,初始为挂起状态(pending state) ,这表示异步操做还没有结束。一个挂起的 Promise 也被认为是未决的(unsettled )。一旦异步操做结束, Promise就会被认为是已决的(settled ) ,并进入两种可能状态之一:this
内部的[[PromiseState]]
属性会被设置为"pending"
、 "fulfilled"
或 "rejected",以反映
Promise的状态。该属性并未在 Promise 对象上被暴露出来,
所以你没法以编程方式判断 Promise
到底处于哪一种状态。不过你可使用then()
方法在 Promise 的状态改变时执行一些特定操做。spa
then()方法调试
then()
方法在全部的 Promise 上都存在,而且接受两个参数。第一个参数是 Promise 被完成时要调用的函数,异步操做的结果数据都会被传入这个完成函数。第二个参数则是 Promise 被拒绝时要调用的函数,与完成函数类似,拒绝函数会被传入与拒绝相关联的任何附加数据。then()方法的两个参数是可选的,所以能够自由组合监听完成和失败的处理函数;code
catch()方法
Promise有catch()方法,等同于只传递拒绝处理函数给then()方法:
promise.catch(function(err) {
// 拒绝
console.error(err.message);
});
// 等同于:
promise.then(null, function(err) {
// 拒绝
console.error(err.message);
});
复制代码
建立未决的Promise
使用Promise构造器能够建立一个Promise实例,此构造器接收一个参数:一个被称之为执行器(excutor)的函数,该函数包含了resolve()
函数和reject()
函数这两个参数。resolve()
函数在异步任务执行成功时调用,而reject()
函数在异步任务执行失败时调用。例如:
let promise = new Promise(function(resolve,reject){
console.log('hi, promise');
resolve();
});
promise.then(()=>{
console.log('hi, then');
});
console.log('hi');
输出:
hi, promise
hi
hi then
复制代码
从输出结果能够看出,Promise构造器中的代码是最早执行的,而then()
代码是最后执行的,这是由于只有在Promise中的处理器函数执行结束以后,then()方法中的完成处理函数或者拒绝处理函数才会添加到做业队列的尾部。
建立已决的Promise
Promise.resolve()
Promise.resolve()
方法接收一个参数,并会返回一个处于已完成状态的 Promise
,在then()
方法中使用完成处理函数才能提取该完成态的Promise
传递的值,例如:
let promise = Promise.resolve('hi');
promise.then((value)=>{
console.log(value); //hi
});
复制代码
可使用Promise.reject()
方法来建立一个已拒绝状态的Promise
,一样只有在拒绝处理函数中或者catch()
方法中才能接受reject()
方法传递的值:
let reject = Promise.reject('reject');
reject.catch((value)=>{
console.log(value); //reject
})
复制代码
非Promise的thenable
当一个对象拥有一个能接受resolve
与reject
参数的then()
方法时,该对象就会被认为是一个非Promise
的thenable
,例如:
let thenable = {
then:function(resolve,reject){
resolve('hi');
}
}
复制代码
Promise.resolve()
与Promise.reject()
方法都可以接受非Promise的thenable做为参数,当传入了非Promise的thenable时,这些方法会建立一个新的Promise,而且可使用then()方法对不一样状态进行操做:
建立一个已完成的Promise
let thenable = {
then:function(resolve,reject){
resolve('hi');
}
}
let promise = Promise.resolve(thenable);
promise.then((value)=>{
console.log(value); //hi
});
复制代码
一样利用thenable能够建立一个已拒绝的Promise:
let thenable = {
then:function(resolve,reject){
reject('hi');
}
}
let promise = Promise.resolve(thenable);
promise.then(null,(value)=>{
console.log(value);
});
复制代码
执行器错误
当执行器内部抛出错误,那么Promise的拒绝处理函数就会被调用,例如:
let promise = new Promise(function(resolve,reject){
throw new Error('Error!');
})
promise.catch(function(msg){
console.log(msg); //error
})
复制代码
除了使用单个Promise外,多个Promise能够进行级联使用,实际上then()
方法或者catch()
方法会返回一个新的Promise,仅当前一个Promise被决议以后,后一个Promise才会进行处理。
串联Promise
let p1 = new Promise(function(resolve,reject){
resolve('hi');
});
p1.then((value)=>{
console.log(value);
throw new Error('Error!');
}).catch(function(error){
console.log(error);
})
复制代码
能够看出当p1的then()
方法执行结束后会返回一个Promise,所以,在此基础上能够继续执行catch()
方法。同时,Promise链容许捕获前一个Promise的错误。
Promise链中传递值
**Promise链的另外一个重要方面是能从一个Promise传递数据给另外一个Promise的能力。**前一个Promise的完成处理函数的返回值,传递到下一个Promise中。
//Promise链传递值
let p1 = new Promise(function(resolve,reject){
resolve(1);
})
p1.then(value=>value+1)
.then(value=>{
console.log(value);
})
复制代码
p1的完成处理函数返回了value+1
,也就是2
,会传入到下一个Promise的完成处理函数,所以,第二个then()
方法中的完成处理函数就会输出2
。拒绝处理函数一样能够被用于在Promise链中传递数据。
Promise链中传递Promise
在完成或者拒绝处理函数中能够返回基本类型值,从而能够在Promise链中传递。另外,在Promise链中也能够传递对象,若是传递的是Promise对象,就须要额外的处理:
传递已完成状态的Promise:
let p1 = new Promise(function(resolve,reject){
resolve(1);
});
let p2 = new Promise(function(resolve,reject){
resolve(2);
})
p1.then(value=>{
console.log(value);
return p2;
}).then(value=>{
console.log(value);
});
输出:1 2
复制代码
p1中返回了Promise对象p2
,当p2
完成时,才会调用第二个then()
方法,将值value
传到完成处理函数中。若Promise
对象p2
被拒绝后,第二个then()
方法中的完成处理函数就不会执行,只能经过拒绝处理函数才能接收到p2传递的值:
let p1 = new Promise(function(resolve,reject){
resolve(1);
});
let p2 = new Promise(function(resolve,reject){
reject(2);
})
p1.then(value=>{
console.log(value);
return p2;
}).catch(value=>{
console.log(value);
});
复制代码
若是想监视多个Promise的状态,从而决定下一步动做,可使用ES6提供的两个方法:Promise.all()
和Promise.race()
;
Promise.all()
Promise.all()方法能接受单个可迭代对象(如数组)做为参数,可迭代对象的元素都是Promise。该方法会返回一个Promise,只有传入全部的Promise都已完成,所返回的Promise才会完成,例如:
//Promise.all()
let p1 = new Promise(function(resolve,reject){
resolve(1);
})
let p2 = new Promise(function(resolve,reject){
resolve(2);
})
let p3 = new Promise(function(resolve,reject){
resolve(3);
})
let p4 = Promise.all([p1,p2,p3]);
p4.then(value=>{
console.log(Array.isArray(value)); //true
console.log(value); //[1,2,3]
})
复制代码
对 Promise.all()
的调用建立了新的Promise p4
,在 p1
、 p2
与 p3
都被完成后, p4
最终会也被完成。传递给 p4
的完成处理函数的结果是一个包含每一个决议值(1 、 2 与 3 ) 的数组,这些值的存储顺序保持了待决议的 Promise
的顺序(与完成的前后顺序无关) ,所以你能够将结果匹配到每一个Promise
。
若传递给Promise.all()
的某个 Promise 被拒绝了,那么方法所返回的 Promise 就会马上被拒绝,而没必要等待其余的 Promise 结束:
//Promise.all()
let p1 = new Promise(function(resolve,reject){
resolve(1);
})
let p2 = new Promise(function(resolve,reject){
reject(2);
})
let p3 = new Promise(function(resolve,reject){
resolve(3);
})
let p4 = Promise.all([p1,p2,p3]);
p4.catch(value=>{
console.log(Array.isArray(value)); //true
console.log(value); //2
})
复制代码
在此例中, p2 被使用数值 2 进行了拒绝,则 p4 的拒绝处理函数就马上被调用,而不会 等待 p1 或 p3 结束执行(它们仍然会各自结束执行,只是 p4 不等它们) 。
拒绝处理函数总会接受到单个值,而不是一个数组。该值是被拒绝的Promise所返回的拒绝值。
Promise.race()
Promise.race()
方法接收一个元素是Promise的可迭代对象,并返回一个新的Promise。一旦传入Promise.race()
的可迭代对象中有一个Promise是已决状态,那么返回的Promise对象就会马上成为已决状态。
而Promise.all()
方法得必须等到全部传入的Promise所有变为已决状态,所返回的Promise才会已决。
let p1 = new Promise(function(resolve,reject){
resolve(1);
})
let p2 = new Promise(function(resolve,reject){
resolve(2);
})
let p3 = new Promise(function(resolve,reject){
resolve(3);
})
let p4 = Promise.race([p1,p2,p3]);
p4.then(value=>{
console.log(Array.isArray(value)); //false
console.log(value); //1
})
复制代码
Promise.race() 方法传入的Promise中哪个Promise先变成已完成状态,就会将值传递给所返回的Promise对象的完成处理函数中。若哪个Promise最早变成已拒绝状态,一样的,会将值传递给p4
的拒绝处理函数中。
能够继承Promise实现自定义的Promise,例如:
class MyPromise extends Promise {
// 使用默认构造器
success(resolve, reject) {
return this.then(resolve, reject);
}
failure(reject) {
return this.catch(reject);
}
}
let promise = new MyPromise(function(resolve, reject) {
resolve(42);
});
promise.success(function(value) {
console.log(value); // 42
}).failure(function(value) {
console.log(value);
});
复制代码
在此例中, MyPromise 从 Promise 上派生出来,并拥有两个附加方法。 success()
方法模拟了 resolve()
, failure()
方法则模拟了 reject()
。
Promise 具备三种状态:挂起、已完成、已拒绝。一个 Promise
起始于挂起态,并在成功时转为完成态,或在失败时转为拒绝态。 then()
方法容许你绑定完成处理函数与拒绝处理函数,而 catch()
方法则只容许你绑定拒绝处理函数;
可以将多个Promise串联起来组成Promise链,而且可以在中间传递值,甚至是传递Promise对象。 then() 的调用都建立并返回了一个新的 Promise ,只有在前一个 Promise 被决议过,新 Promise 也会被决议。 同时也可使用Promise.all()和Promise.race()方法来管理多个Promise。