相信很多前端都对promise非常熟悉,对于promise的特性也都有一定的理解,但是说到手动实现promise,这对不少人应该是一个挑战,莫急,复杂的事其核心往往很简单,复杂是因其容错处理的解决思路。
要手动实现promise就不得不来了解promiseA+规范了。
promise/A+规范
在学习promise/A+规范前我们先了解一下术语,以便理解下面规范中的统一概念
1,promise是一个有then方法的对象或函数,行为遵循本规范
2,thenable 是一个有then方法的对象或者是函数
3,value是promise状态成功时的值,也就是resolve的参数,包括更熟数据类型,也包括undefined/thenable或者是promise
4,reason是promise状态失败时的值,也就是reject的参数,表示拒绝的原因
5,exception是一个使用throw抛出的异常值
接下来将分下面几部分来阐述promise/A+规范
Promise status
promise有三种状态,我们要注意他们之间的流转关系
pending
- 初始的状态,可改变
- 一个promise在resolve或者reject前都处于这个状态
- 可以通过resolve===》fulfilled状态
- 可以通过reject===》rejected状态
fulfilled
- 最终态,不可变
- 一个promise被resolve后会变成的状态
- 必须拥有一个value值
rejected
- 最终态,不可变
- 一个promise被reject后会变成的状态
- 必须拥有一个reason
Tips:总结,promise状态流转过程
pending -> resolve(value) -> fulfilled
pending -> reject(reason) -> rejected
then
promise提供的一个then方法,用来访问最终结果,无论是value还是reason
如:
参数要求
- onFulfilled必须是函数类型,如果不是函数,应被忽略
- onRejected必须是函数类型,如果不是,应被忽略
onFulfilled特性
- 在promise变成fulfilled时,应调用onFulfilled,参数为value
- 在promise变成fulfilled之前,不应该被调用
- 只能被调用一次
onRejected特性
- 在promise变成rejected时,应该调用onRejected,参数为reason
- 在promise变成rejected之前,不应被调用
- 只能被调用一次
onFulfilled和onRejected应是微任务,这里将使用queueMicrotask来实现微任务的调用
then方法可以被调用多次
- promise状态变成fulfilled后,所有的onFulfilled回调都需要按照then的顺序执行,也就是按照注册顺序执行
- promise状态变成rejected后,所有的onRejected回调都需要按照then的顺序执行,按照注册顺序执行
在实现过程中需要一个数组来存放多个onFulfilled或者是onRejected的回调
返回值
then应返回一个promise
- onFuifilled或者onRejected执行的结果为x,调用resolvePromise
- 如果onFulfilled或者onRejected执行时抛出异常e,promse2需要被reject
- 如果onFulfilled不是一个函数,promise2以promise1的value触发fulfilled
- 如果onRejected不是一个函数,promise2以promise1的reason触发rejected
resolvePromise
- 如果promise2与x相等,那么reject TypeError
- 如果x是一个promise。如果x是pending态,那么promise必须要在pending,直到x变成fulfilled or rejected;如果x被fulfilled,fulfill promise with the same value;如果x被rejected,reject promise with the same reason
- 如果x是一个object或者是一个function;let then=x.then ;如果x.then这步出错,那么reject promise with e as the reason;如果then是一个函数,then.call(x,resolvePromiseFn,rejectPromise),resolvePromiseFn的入参是y,执行resolvePromise(promise2,y,resolve,reject);rejectPromise的入参是r,reject promise with r.如果resolvePromise和rejectPromise都调用,那么第一个调用优先,后面调用忽略。如果调用then抛出异常e时,如果resolvePromise已经被调用,忽略,reject promise with e as then reason。如果then不是一个function,fulfill promise with x。
小伙伴们是否对resolvePromise的各个可能性分析有些疑惑和不解,莫急,我们一步一步来通过代码来辅助理解它。理解promise/A+规范,是我们手写promise的基础。下一章我们来手动实现promise.