一、Promise规范
Promise是用于处理异步场景的规范,能有效的避免产生回调地狱的问题,使异步代码看起来更加简洁、清晰、统一 且易于维护。
Promise可以将一个异步任务包装成一个Promise对象。
有哪些是异步任务❓
最常见的例如远程请求、延时弹窗等
Promise规范认为每个异步任务对象都应该有两个阶段和三种状态。
两个阶段
- 未决阶段 -
unsettled表示还未决定当前Promise的对象状态 - 已决阶段 -
settled表示已经决定当前Promise的对象状态
三种状态
- 挂起状态(未决阶段) -
pending - 完成状态(已决阶段) -
fulfilled - 失败状态(已决阶段) -
rejected
他们之间存在以下逻辑:
- 任务只能从未决阶段变为已决阶段,无法逆行
- 任务只能从挂起状态变为完成状态或失败状态,无法逆行
- 任务一旦完成或者失败,状态就固定下来了,无法改变
例如:
pending -> fulfilled ✅
pending -> rejected ✅
fulfilled -> pending ❎
状态改变
从pending挂起到fulfilled成功完成,称为resolve
从pending挂起到rejected失败完成,称为rejected
后续状态
Promise可以针对任务结果进行后续处理,处理成功后的状态称为onFulfilled,处理失败后的状态称为onRejected
二、实现Promise规范
基于以上的Promise规范,ES6给我们提供了一套API:
const p = new Promise((resolve, reject) => {
// 将promise状态改为成功
resolve('success')
})
const p = new Promise((resolve, reject) => {
// 将promise状态改为失败
reject('error')
})
resolve(data)携带的数据为需要传递的相关数据,例如上面的代码resolve('success')将会把"success"这个字符串携带到then(data => {})的第一个函数回调中;
reject(err)携带的数据为失败的原因,会把这个失败的原因携带到then(data => {}, err => {})的第二个回调函数中;
p.then(
// 针对fulfilled状态的回调
(data) => {
console.log(data);
},
// 针对rejected状态的回调
(errMsg) => {
console.log(errMsg);
}
);
三、关于链式调用
对于Promise失败的处理,除了.then(null, err => {})的第二个函数回调,还可以使用链式调用.catch()来处理,代码如下
p.then(
// 针对fulfilled状态的回调
(data) => {
console.log(data);
}
).catch(
// 针对rejected状态的回调
(errMsg) => {
console.log(errMsg);
}
);
.then()方法同时也会返回一个新的Promise对象,也可以针对这个返回的Promise对象进行后续处理。
关于用.then()之后返回的新Promise的状态
-
若没有相关的后续任务,新的Promise的状态和前任务一致,数据为前任务返回的数据
const p = new Promise((resolve, reject) => { reject("error"); }); const p2 = p.then((data) => {});以上代码,此时p2的状态为
Promise {<rejected>: 'error'},由于返回的第二个Promise对象没有对第一个Promise对象做错误处理,所以新的Promise对象状态和第一个Promise对象状态一致。const p = new Promise((resolve, reject) => { resolve("success"); }); const p2 = p.catch((err) => { console.log(err); });以上代码,此时p2的状态为
Promise {<fulfilled>: 'success'},由于返回的第二个Promise对象没有对第一个Promise对象做成功处理,所以新的Promise对象的状态和第一个Promise一致,且数据为第一个Promise对象返回的数据。 -
若有后续任务未执行,新任务为挂起状态
const p = new Promise((resolve, reject) => { setTimeout(() => { resolve("success"); }, 2000); }); const p2 = p.then((data) => { console.log(data); });以上代码,第一个Promise对象需要再2秒之后才能确定状态,所以在这2秒内,p2的Promise对象状态为
Promise {<pending>},2秒之后状态会转变为Promise {<fulfilled>}。 -
若后续任务执行了,则根据执行有错无错,来判断新的Promise状态
const p = new Promise((resolve, reject) => { resolve("success1"); }); const p2 = p.then((data) => { console.log(data); return "success2"; });以上代码,针对第一个Promise对象进行了处理,并且返回了success2,那么此时p2的Promise对象状态为
Promise {<fulfilled>: 'success2'}。const p = new Promise((resolve, reject) => { resolve("success1"); }); const p2 = p.then((data) => { console.log(data); throw new Error("error"); });以上代码,针对第一个Promise对象进行了处理,但处理过程中有错,那么此时p2的Promise对象状态为
Promise {<rejected>}。 -
若后续任务返回了一个新的Promise任务对象,那么新的任务状态和数据与该返回的Promise任务对象一致
const p = new Promise((resolve, reject) => { resolve("success1"); }); const p2 = p.then((data) => { return new Promise((resolve, reject) => { resolve("success2"); }); });以上代码,针对第一个Promise对象的后续处理,返回了一个新的Promise对象,那么此时p2的状态就与返回的这个新的Promise对象状态一致,新Promise对象成功p2就成功,新Promise对象失败p2也就失败。
四、Promise的静态方法
| 方法名 | 作用 |
|---|---|
| Promise.resolve(data) | 直接返回一个完成状态的任务 |
| Promise.reject(reason) | 直接返回一个拒绝状态的任务 |
| Promise.all([Promise1, Promise2]) | 返回一个任务 任务数组全部成功则成功 任何一个失败则失败 |
| Promise.any([Promise1, Promise2]) | 返回一个任务 任务数组任一成功则成功 任务全部失败则失败 |
| Promise.allSettled([Promise1, Promise2]) | 返回一个任务 任务数组全部已决则成功 该任务不会失败 |
| Promise.race([Promise1, Promise2]) | 返回一个任务 任务数组任一已决则已决,状态和其一致 |
下一期复习手写Promise