先前实现过 最简实现 Promise 支持链式调用,这次我们来实现完整的
Promise
前提
在熟悉 Promise 的前提下,我们知道 Promise 底层内部维护了三种状态:PENDING
代表异步状态待定
REJECTED
代表异步状态拒绝
FULFILLED
代表异步状态解决
以及内部维护了
外部传入对应 resolve 回调数组 : resolveCallbacks
外部传入对应 reject 回调数组 : rejectCallbacks
以及最重要的三个 then, resolve, reject 方法
先实现最简单的 resolve reject :如下
1 | const FULFILLED = 'FULFILLED' |
Promise.prototype.then()
先上 then 的代码
1 | then(onFulfilled, onRejected) { |
这里的 queueMicrotask 是原生 api,为了模拟浏览器下微任务执行。而 resolvePromise 是为了抽离可复用逻辑,目的做 promise 的一些边际处理及逻辑判断。
按照 Promise/A+规范,需要在 then 调用的时候,返回新的一个 Promise,并在内部判断 state 的状态,做对应处理。
- 判断 then 方法的两个参数 onRejected 和 onFulfilled 是否为 function。
1.1 onRejected 和 onFulfilled 都是 function,继续执行下一步。
1.2 onRejected 不是 function,将 onRejected 赋值为箭头函数,参数为 reason 执行 throw reason
1.3 onFulfilled 不是 function,将 onFulfilled 赋值为箭头函数,参数为 value 执行 return value- 当前 Promise 状态为 rejected:
2.1 onRejected 方法传入 this.reason 参数,异步执行。
2.2 对执行的 onRejected 方法做容错处理,catch 错误作为 reject 方法参数执行。 3.当前 Promise 状态为 fulfilled:
3.1 onFulfilled 方法传入 this.value 参数,异步执行。
3.2 对执行的 onFulfilled 方法做容错处理,catch 错误作为 reject 方法参数执行。- 当前 Promise 状态为 pending:
4.1 收集 onFulfilled 和 onRejected 两个回调函数分别 push 给 resolveCallbacks 和 rejectCallbacks。
4.2 收集的回调函数同样如上所述,先做异步执行再做容错处理。- 返回一个 Promise 实例对象。
Promise 解决程序(resolvePromise 方法)
代码如下:
1 | function resolvePromise(p2, x, resolve, reject) { |
- 如果 x 和 promise 引用同一个对象:
1.1 调用 reject 方法,其参数为 new TypeError()- 如果 x 是一个 promise 或 x 是一个对象或函数:
2.1 定义一个 called 变量用于记录 then.call 参数中两个回调函数的调用情况。
2.2 定义一个 then 变量等于 x.then
2.3 then 是一个函数。使用 call 方法绑定 x 对象,传入解决回调函数和拒绝回调函数作为参数。同时利用 called 变量记录 then.call 参数中两个回调函数的调用情况。
2.4 then 不是函数。调用 resolve 方法解决 Promise,其参数为 x
2.5 对以上 2.2 检索属性和 2.3 调用方法的操作放在一起做容错处理。catch 错误作为 reject 方法参数执行。同样利用 called 变量记录 then.call 参数中两个回调函数的调用情况。- 如果 x 都没有出现以上两种状况:
调用 resolve 方法解决 Promise,其参数为 x- called 变量的作用:根据 Promise A+ 2.3.3.3.3 规范:两个参数作为函数第一次调用优先,以后的调用都会被忽略。
因此我们在以上两个回调函数中这样处理:
已经调用过一次:此时 called 已经为 true,直接 return 忽略
首次调用:此时 called 为 undefined,调用后 called 设为 true
注意:2.3 中的 catch 可能会发生(两个回调函数)已经调用但出现错误的情况,因此同样按上述说明处理。
Promise.all()
代码如下:
1 | static all(promises) { |
Promise.race()
代码如下:
1 | static race(promises) { |
Promise.allSettled()
代码如下:
1 | static allSettled(promises) { |
Promise.any()
代码如下:
1 | static any(promises) { |
结尾
把 Promise 的其他静态方法及原型方法补充完毕后,下载 Promise/A+ 规范的测试用例进行校验即可。
1 | pnpm add promises-aplus-tests -D |