概述
Promise对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。
Promise对象有三种状态:pending(初始状态)、fulfilled(成功状态)、rejected(失败状态)。
Promise对象的状态一旦由pending变为fulfilled或rejected将无法再更改。
Promise对象的状态变为fulfilled后,通过then()方法执行回调函数;状态变为rejected后,通过catch()方法执行回调函数。
在 ES2018 中引入了finally(),表示该Promise执行结束后(无论是"then"还是"catch"导致的结束)都会执行传入finally方法的回调函数,回调函数无参数。
简单示例
创建
通过new运算符可以创建Promise实例,唯一参数是带有 resolve和reject两个参数的 executor函数。resolve和reject函数被调用时,分别将Promise的状态改为fulfilled(完成)或rejected(失败),两个函数都接受一个参数,作为成功(或失败)的信息传递给对应的处理方法(then或catch)。
let p = new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve('resolve');
} else {
reject('reject');
}
}, 1000);
});上述例子中,1 秒后随机把Promise对象的状态改为fulfilled(完成)或rejected(失败)。
处理
被创建的Promise对象会立即执行executor函数,如果我们还需要在该异步函数结束后再做点什么,就需要调用Promise对象的then()、catch()和finally()方法。(三个方法都会返回一个新的Promise对象,因此能使用"链式操作")
接上例子:
p.then(res => {
console.log(res); // 'resolve'
}).catch(err => {
console.log(err); // 'reject'
}).finally(()=>{
console.log('finally'); // 必定执行
});可以看出,then()和catch()方法传入的是一个回调函数,该回调函数有唯一参数,对应的是resolve和reject函数传入的参数。finally()同样是传入一个对调函数,不同的是该回调函数无参数。
几种场景
场景1:多个Promise需要依次执行。(Promise.prototype.then()可以传入另一个Promise对象)
const promise1 = new Promise(...);
const promise2 = new Promise(...);
const promise3 = new Promise(...);
// promise1成功执行后再执行promise2,再是promise3
promise1.then(promise2).then(promise3);场景2:多个Promise需要都成功。(静态方法:Promise.all())
const promise1 = new Promise(...);
const promise2 = new Promise(...);
const promise3 = new Promise(...);
// promise1/2/3 均成功后再执行 then ( 其中一个失败也不会执行 then )
Promise.all([promise1, promise2, promise3]).then(callback(){...});场景3:多个Promise只需要其中一个成功。(静态方法:Promise.race())
const promise1 = new Promise(...);
const promise2 = new Promise(...);
const promise3 = new Promise(...);
// promise1/2/3 任意一个成功后执行 then
Promise.race([promise1, promise2, promise3]).then(callback(){...})
Promise.resolve()
Promise.resolve()用于生成一个状态为fulfilled的Promise对象。其参数与.prototype.resolve()一致。
let p1 = Promise.resolve('resolve');
// 等效如下代码
let p2 = new Promise((resolve, reject) => {
resolve('resolve');
});Promise.reject()
Promise.reject()用于生成一个状态为rejected的Promise对象。其参数与.prototype.reject()一致。
let p1 = Promise.reject('resolve');
// 等效如下代码
let p2 = new Promise((resolve, reject) => {
reject('resolve');
});继续深入了解
then() 的第二个参数
其实上面的介绍中,完全没有提及then()的第二个参数,因为其作用与catch()方法一致。看下面例子:
let p = new Promise((resolve, reject) => {
reject('reject');
})
p.then(res => { }, err => {
console.log(err); // 'reject'
});
p.catch(err => {
console.log(err); // 'reject'
});
不传参的 then()/catch()/finally()
当then()/catch()/finally()不传入参数,都会返回与原Promise对象相同(但不相等)的新Promise对象。看如下例子:
// 不传参的"then"
let p1 = Promise.resolve('resolve');
let p2 = p1.then();
p2.then(res => {
console.log(res); // 'resolve'
});
console.log(p1 === p2); // false
// 不传参的"catch"
let p3 = Promise.reject('reject');
let p4 = p3.catch();
p4.catch(res => {
console.log(res); // 'reject'
});
console.log(p3 === p4); // false
// 不传参的"finally"
let p5 = Promise.resolve('resolve');
let p6 = p5.finally();
p6.then(res => {
console.log(res); // 'resolve'
});
console.log(p5 === p6); // false
then()/catch()/finally() 的参数是带返回值的回调函数
当then()或catch()的参数是有返回值的回调函数A,then()或catch()会返回一个状态为fulfilled的Promise对象。新Promise对象的then()方法的回调函数的参数就是回调函数A的返回值。
注意,状态为reject的Promise对象在then()的第一个对调函数返回会导致报错。
注意,finally()的对调函数"return"并不会影响新的Promise对象的then()或catch()方法的回调函数的参数值。
如果觉得文字描述有点绕,看下面例子:
// 'resolve'状态被处理后的'return'
Promise.resolve('resolve').then(() => {
return 'return1'
}).then(res => {
console.log(res)
}); // 'return1'
// 'reject'状态被处理后的'return'
Promise.reject('resolve').catch(() => {
return 'return2'
}).catch(err => {
console.log('catch:', err)
}).then(res => {
console.log('then:', res)
}); // 'then: return2'
// 'finally'的'return'只会返回与原promise相同的对象
Promise.resolve('resolve').finally(() => {
return 'return3'
}).then(res => {
console.log(res)
}); // 'resolve'
// 'reject'状态未被处理的'return'
Promise.reject('reject').then(() => {
return 'return4'
}).then(res => {
console.log(res);
}); // 报错!!.resolve() 的参数
resolve()(包括Promise.reject()和Promise.prototype.reject())除了上面介绍的用法,还能传入thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定。
注意,thenable的then()方法只有传入唯一一个回调函数才会被执行,其他参数会被忽略。
看如下例子:
let thenable = {
then(cb1, cb2) {
cb1('cb1');
cb2('cb2');
}
}
// Promise.resolve()
Promise.resolve(thenable).then(
res1 => {
console.log(res1); // 'cb1'
},
res2 => {
console.log(res2); // 不会执行
}
).catch(err => {
console.log(err); // 不会执行
});
// Promise.prototype.resolve()
new Promise((resolve, reject) => {
resolve(thenable);
}).then(res => {
console.log(res); // 'cb1'
});