深入Promise
Promise/A+规范
Promise 规范有很多,如 Promise/A,Promise/B,Promise/D 以及 Promise/A 的升级版 Promise/A+,有兴趣的可以去了解下,最终 ES6 中采用了 Promise/A+ 规范。在讲解 Promise 实现之前,当然要先了解 Promise/A+ 规范。Promise/A+ 规范参考:
其中有几个要点需要注意一下:
- Promise 本质是一个状态机。每个 promise 只能是 3 种状态中的一种:pending、fulfilled 或 rejected。状态转变只能是 pending -> fulfilled 或者 pending -> rejected。状态转变不可逆
- then 方法可以被同一个 promise 调用多次。
- then 方法必须返回一个 promise。规范里没有明确说明返回一个新的 promise 还是复用老的 promise(即 return this),大多数实现都是返回一个新的 promise,而且复用老的 promise 可能改变内部状态,这与规范也是相违背的。
实现一个简单的Promise
Promise 初始化
Promise对象存在3中状态:
- Pending(进行中)
- Fulfilled(已成功)
- Rejected(已失败)
状态只能由
Pending
变为Fulfilled
或由Pending
变为Rejected
,且状态改变之后不会在发生变化,会一直保持这个状态。
resolve和reject
- resolve: 将promise对象的状态从Pending(进行中)变为Fulfilled(已完成)
- reject: 将Promise对象的状态从Pending(进行中)变为Rejected(已失败)
- resolve 和 reject 都可以传入任意类型的值作为实参,表示 Promise 对象成功(Fulfilled)和失败(Rejected)的值
1 | /** |
这样我们就是实现了Promise状态和值的改变。接下来我们要实现Promise和核心:then方法
完善Promise
实现Promise的then方法,Promise对象的then方法接受两个参数:
1 | promise.then(onFulfilled, onRejected) |
then方法中的两个参数如果不是函数,则必须被忽略。
- 如果onFulfilled是函数,则当Promise状态变为成功时,必须被调用,其中第一个参数为Promise成功状态传入的值(即resolve的值),只可以被调用一次。
- 如果onRejected是函数,则当Promise状态变为失败时,必须被调用,其中第一个参数为Promise失败状态传入的值(即reject的值),只可以被调用一次
- then方法可以被同一个Promise对象调用多次,当Promise状态变为成功时,所有onFulfilled按照注册顺序依次回调;当Promise状态变为失败时,所有onRejected按照注册顺序依次回调
- then 方法必须返回一个Promise(在ES6 以及大多数实现中都是返回一个新的Promise),因此Promise的then方法支持链式调用
特殊的需要注意Promise的值传递以及错误传递的机制。
修改构造函数:增加执行队列
1 | constructor (fn) { |
添加then方法,并且需要将回调函数加入到执行队列中:
1 | then (onFulfilled, onRejected) { |
完善then方法:
1 | then (onFulfilled, onRejected) { |
then方法算是Promise的核心,then方法除了必须返回一个新的Promise之外(以便链式调用);需要注意then中注册的两个回调函数也可能是一个Promise~;以上then函数的代码需要参照Promise的定义认真琢磨!
接着修改 _resolve 和 _reject :依次执行队列中的函数
当 resolve 或 reject方法执行时,我们依次提取成功或失败任务队列当中的函数开始执行,并清空队列,从而实现 then 方法的多次调用,实现的代码如下:
1 | _resolve (val) { |
这里还有一种特殊的情况,就是当 resolve方法传入的参数为一个 Promise对象时,则该 Promise对象状态决定当前Promise对象的状态。我们需要修改_resolve来支持这样的特性:
1 | _resolve (val) { |
这样一个基本的Promise就实现了。我们可以为他添加一些其他的方法
catch方法
相当于调用then方法,只需要注册Rejected状态的回调函数
1 | // 添加catch方法 |
静态resolve方法
1 | // 添加静态resolve方法 |
静态rejected方法
1 | // 添加静态reject方法 |
静态all方法
1 | // 添加静态all 方法 |
静态race方法
1 | static race (list) { |
finally方法
finally 方法用于指定不管 Promise对象最后状态如何,都会执行的操作
1 | finally (cb) { |
这样一个完整的Promise就实现了~
完整代码如下:
1 | /** |
参考: