本文将剖析 Promise 的内部结构,实现符合 Promises/A+ 规范的 Promise,并且通过 promises-aplus/promises-tests 测试。
JavaScript Promise 标准解读
Promise 表示一个异步操作的最终结果,与之进行交互的方式主要是 then
方法,该方法注册了两个回调函数,用于接收 Promise resolve 的终值或者 Promise reject 的原因。
Promise States
- 一个 Promise 的当前状态必须为以下三种状态中的一种:
- PENDING
- FULFILLED
- REJECTED
- Promise 的初始状态为 PENDING,由此状态可转换为 FULFILLED 或者 REJECTED,一旦状态确定,就不能再次转换为其他状态,此状态称之为 settle
then
方法
一个 Promise 必须提供
then
方法,该方法接收两个参数:1promise.then(onFulfilled, onRejected)then
方法必须返回一个 Promise 对象1promise2 = promise1.then(onFulfilled, onRejected)
The Promise Resolution Procedure
不同实现的 Promise 需要可以无缝相互调用(interoperable),例如:
实现 Promise
Promise 构造函数
|
|
- 构造函数中,
_onResolvedCb
和_onRejectedCb
属性分别为 Promise resolved/rejected 的回调函数集,因为在 Promise 结束(settle)之前,可能有多个then
挂在该 promise 上,即有多个回调事件; - 构造函数接收一个 executor 函数,函数中的操作执行结束后,若成功,调用 resolve 并传入 value;若失败,调用 reject 并传入 reason
接下来实现 resolve
和 reject
这两个函数,这两个函数类似,首先判断当前 Promise 状态后,变更其状态;并记录 resolved 的终值和 rejected 的原因;最后执行回调函数
then
方法
Promise 对象的 then
方法用来注册 Promise resolved 或者 rejected 后的回调函数,then
方法返回一个新的 Promise 对象
then
方法返回的新 Promise 对象中,需要根据前一个 Promise 对象的不同状态来处理:- 若是 FULFILLED,则直接执行
onResolved
回调函数。如果onResolved
的返回值又是一个 Promise 对象,那么继续通过then
方法构造 Promise 链;否则,调用resolve
函数结束新的 Promise 对象 - 若是 REJECTED,处理逻辑同 FULFILLED
- 若是 PENDING,则将
onResolved
和onRejected
回调函数放到回调函数集中
- 若是 FULFILLED,则直接执行
最终得到如下简易版本的 then
方法:
代码剖析注意:
1、then
方法的两个回调函数执行过程中可能抛出异常,所以在执行时,需要 try-catch
包起来
2、Promise 值穿透
如上代码正确的执行结果为输出:1;注意到第一个 then
方法并没有传入回调函数,所以在执行的时候,会抛出异常,提示:TypeError: onResolved is not a function
;在添加 try-catch
后,可以正常执行;catch 到异常后,执行 reject(e)
,于是第二个 then
方法中的 reject 回调函数执行了。
为了解决这个问题,我们需要判断 then
方法传入的两个参数是否为函数,若不是,直接返回 value 或者抛出 reason。
不同 Promise 的交互
then
方法传入的两个回调函数 onResolved
和 onRejected
执行后,返回值 x
可能是一个 Promise 对象,也即是 thenable
,为了确保调用 x
上的 then
方法成功,我们需要实现标准中 2.3.The Promise Resolution Procedure 的内容,这样即使实现方式不同,但遵循标准,不同实现的 Promise 之间就可以交互使用了。
标准对此说明的非常详细,对照着标准阅读以下代码,有助理解。
在 then
方法中需要修改,onResolved
和 onRejected
执行后,调用如上的 resolvePromise (promise2, x, resolve, reject)
方法
Promises/A+ test
Promises/A+ 规范提供了一个测试规范: promises-aplus/promises-tests
测试需要提供一个 adapter 方法 Promise.deferred
执行:
代码
- 简易版(没有实现 Promises/A+ 标准 2.3.The Promise Resolution Procedure)
YingshanDeng / simple-promise.js - 完整版(完全通过 Promises/A+ 测试规范)
YingshanDeng/Promise