Hi,又是我,之前那篇手撸promise写的太简单,被同学吐槽了,说完全没按照规范来,好的,先在这里翻译下规范
原文 https://promisesaplus.com/
时间 2018年11月29日
一个promise代表一个异步操作的最终结果,和promise交互的主要方法是通过它的then方法,then方法是用户注册的回调函数,接收promise的最终结果或者promise没有fulfilled的原因
本规范详细描述了then方法的行为,提供了一个可互操作的基础,所有符合Promises/A+的实现都可以依赖它来提供。
核心Promises/A+规范不处理如何创建、fulfill或reject promise,而是聚焦于then方法,将来的规范可能涉及其他方面。
-
技术
- 1.1 promise是一个行为符合本规范的,具有then方法的对象或者函数
- 1.2 thenable是一个定义了then方法的对象或者函数
- 1.3 value是任何合法的js类型,包括undefined,thenable或者promise
- 1.4 exception是通过throw抛出的值
- 1.5 reason是promise rejected时的值
-
要求
-
2.1 Promise状态
一个pomise必须处于以下三种状态之一:pending、fulfilled、rejected
-
pending,可以转换为fulfilled或rejected
-
fulfilled,不能转换为其他状态,必须有一个不变的value
-
rejected,不能转换为其他状态,必须有一个不变的reason
不变的(reason或者value)的意思是immutable identity (i.e.
===
),但不意味着 deep immutability
-
-
2.2 then方法
一个promise必须提供一个then方法来接收当前或最终的value或reason
一个promise的then方法接受两个参数
promise.then(onFulfilled, onRejected)
-
onFulfilled和onRejected都是可选参数,当它们不是函数时,必须被忽略
-
如果onFulfilled是函数,它必须在promise fulfilled之后调用,value作为第一个参数,不能多次调用
-
如果onRejected是函数,它必须在promise rejected之后调用,reason作为第一个参数,不能多次调用
-
onFulfilled和onRejected只有在执行上下文只包含平台代码时才能调用 [3.1]
-
onFulfilled和onRejected必须作为函数被调用 (i.e. with no
this
value) [3.2] -
then在一个promise中可能被调用多次
-
onFulfilled和onRejected必须按照then调用时的顺序来执行(注意这里还在说then,没在说catch,通篇都没提catch)
-
then必须返回一个promise [3.3]
promise2 = promise1.then(onFulfilled, onRejected);
(注意下面几句都是对照上面这个例子来说的)
如果onFulfilled或onRejected返回一个value
x
,执行Promise Resolution Procedure[[Resolve]](promise2, x)
;如果onFulfilled或onRejected抛出一个exception
e
,promise2必须rejected,并将e
作为reason;如果onFulfilled不是一个函数,当promise1 fulfilled,promise2必须用和promise1相同的value来fulfilled(大概是在说value要传递给promise2)
如果onRejected不是一个函数,当promise1 rejected,promise2必须用和promise1相同的reason来rejected
-
-
2.3 Promise Resolution Procedure
Promise Resolution Procedure是一个抽象的操作,可以表示为
[[Resolve]](promise, x)
,如果x是一个thenable,它尝试使promise采用x的状态,否则,它使用value x来fulfill promise。运行
[[Resolve]](promise, x)
,要遵循以下内容:-
如果promise和x指向同一个对象,用reason TypeError来reject promise
-
如果x是一个promise,采用它的状态 [3.4]。如果x是pending,promise也是pending,直到x变成fulfilled或rejected;如果x是fulfilled,promise用相同的value fulfill,如果x是rejected,promise用相同的reason reject
-
如果x是对象或者函数,将then方法赋为x.then [3.5]。
-
如果x.then抛出一个exception
e
,用reason e来reject promise。 -
如果then是函数,将x作为this来调用then,第一个参数是resolvePromise,第二个参数是rejectPromise。如果用一个value
y
来调用resolvePromise,运行[[Resolve]](promise, y)
。如果用一个reasonr
来调用rejectPromise,用r来reject promise。如果resolvePromise和rejectPromise都被调用,或者resolvePromise(或rejectPromise)被调用多次,第一个调用优先执行,其他的忽略。如果调用then抛出一个exceptione
,resolvePromise或rejectPromise已经被调用过,忽略这个e,否则用reason e来reject promise。 -
如果then不是函数,用value x来fullfill promise
-
-
如果x不是对象和函数,用value x来fullfill promise
如果thenable引起循环调用,可以用一个TypeError来reject promise [3.6]
-
-
-
注意
- 3.1 这里的平台代码是指引擎、环境和promise实现代码,这个要求确保onFulfilled和onRejected在then 调用后,event loop完成此次循环以后,异步执行。这可以通过setTimeout或setImmediate实现,或者通过MutationObserver或provess.nextTick来实现。因为promise被认为是由平台来实现的,所以它自己可能就包含一个任务调度队列
- 3.2 在严格模式下,onFulfilled和onRejected中的this会是undefined,在非严格模式下,是全局对象
- 3.3 实现可能允许
promise2 === promise1
,这是符合要求的,每种实现都应该标识是否会产生这样的情况、在什么条件下会出现这种情况 - 3.4 通常,只有x是当前promise实现的一个实例时才可以采用其状态,这一条允许使用不同promise实现,但要和当前实现兼容
- 3.5 首先存储x.then的引用,然后测试、调用该引用的过程避免了对x.then属性的多次访问。这种预防措施用于确保x.then的一致性,防止其在使用过程中改变。
- 3.6 实现不应该设置thenable调用链的深度限制,并假定超过限制后调用就是无限循环了。只有真正的循环才应该导致TypeError,如果确实遇到了无限调用的thenable,一直递归是正确的行为