Promise A+规范
Promise A+规范产生于2012年左右,它的产生目的就是希望把异步规范化,并解决回调地狱。在该规范之前,对于异步场景的处理使用了大量的回调函数,有的异步场景也可以把函数保存到对象的属性中,以便将来调用,以此看来,之前处理异步的方式并不统一,于是便有了Promise A+的由来,它并不是一个技术,而是一套规范,对后来的ES6的Promise标准制作提供了参考。 Promise A+规范参考官网:https://promisesaplus.com/
对异步处理的进化
用一张流程图来展示对异步处理的进化:
Promise
一个promise就是一个对象,它用于表示一个异步任务,是一个带有then方法的对象。它有三种状态,pending挂起、fufilled完成、rejected失败。不管任何时候,promise都处于这三种状态的一种,状态介绍下图所示:
状态的转换
任务开始时,始终处于unsettled(未决)阶段的挂起状态,任务在unsettled阶段时可以将其推向settled阶段。比如,当从服务器拿到数据后,我们就从未决阶段推向已决的resolved状态,如果网络不好,导致出错了,我们就从未决阶段推向已决的rejected状态。我们把从未决推向已决的resolved状态的过程,叫做resolve,从未决推向已决的rejected状态的过程,叫做reject。需要主义的是这种状态和阶段的变化是不可逆的,一旦推向了settled就无法修改该阶段的状态。
1. 当promise处于pending状态时,它可以在任何时候把状态转变俄日fufilled 或 rejected。
2. 当promise处于fufilled状态时,它无法再次更改到其他状态,它必须是一个值,表示任务完成时的数据,该数据可以是任何Js数据(包括undefined),一旦该值确定则无法修改。
3. 当promise处于rejected状态时,它无法再次更改到其他状态,它必须是一个值,表示任务失败的原因,该数据可以是任何Js数据(包括undefined),一旦该值确定则无法修改。
让任务到达rejected状态的方式:
a. 调用reject
b. 代码执行报错
c. 抛出错误
转换状态成功后即任务完成后会附带数据,就是上面提到的值,具体展示由下图所示:
任务的后续处理 then方法
对与任务的后续处理,可以通过promise提供的then方法访问到任务完成的值或任务失败的原因。
then方法可以接收两个参数:
promise.then(onFulfilled, onRejected)
1. onFulfilled 和 onRejected 都是可选参数,如果该两个参数不是一个函数,则必须省略。
2. 如果 onFulfilled 是一个函数,它会在 promise 到达 fulfilled 状态时被调用,调用该函数时,应该把任务完成时的值作为第一个参数传递进去(该函数只能被调用一次)。
3. 如果 onRejected 是一个函数,它会在 promise 到达 rejected 状态时被调用,调用该函数时,应该把任务失败的原因作为第一个参数传递进去(该函数只能被调用一次)。
4. onFulfilled 和 onRejected 是异步的,所以要等到当前执行栈清空后才能别调用。
5. 可以多次对同一个 promise 调用 then 方法,从而注册多个 onFulfilled 和 onRejected ,then 方法必须再次返回一个 promise:
promise2 = promise1.then(onFulfilled, onRejected);
再次返回的 promise 的任务状态与 初始的 promise 状态转换时相似。
Promise 面试题
通过promise 面试题将理论与实践相结合:
试题一:
const promise = new Promise((resolve, reject) => {
console.log(1)
resolve("a");
resolve("b");
reject("c")
console.log(2)
})
promise.then(data => {
console.log(data)
}, resean => {
console.log(reason)
})
console.log(4)
试题二:
setTimeout(() => {
console.log(1);
});
var pro = new Promise((resolve, reject) => {
console.log(2);
resolve(3);
console.log(4);
throw 5;
console.log(6);
});
console.log(7);
pro.then(
(data) => {
console.log(data);
},
(reason) => {
console.log(reason);
}
);
如有问题,可在评论区提出,共同讨论。