引言
俗话说好记性不如烂笔头,所以我决定翻译一下Promise/A+
规范,帮助自己更加深刻的理解promise
,为之后手撸promise
源码做准备,同时也希望本篇文章对大家也有所帮助。
正文
这是一个实现者为实施者提供的开源的、可互操作的JavaScript Promise规范
promise
代表一个异步操作的最终结果。与promise
的主要互动方式是通过then
方法注册回调函数来接收promise
的最终值或者promise
未完成的原因。
该规范详细描述了then
方法的行为,它提供了一个可互操作的基础,所有Promises/A
+
符合 promise
的实现都可以依赖于这个基础。因此,该规范被认为是非常稳定的。尽管Promises/A+
的作者可能偶尔会修改规范,对其进行一些向后兼容的小修改,以解决新发现的问题,我们只有在仔细考虑、讨论和测试后,才会集成大型或者不向后兼容的变更。
历史上,Promises/A+
澄清了早期的Promises/A proposal的行为条款,将其拓展到涵盖事实的行为,并且省略了未指定或有问题的部分。
最后,Promises/A+
规范的核心不是处理如何创建、完成或者失败的promises
,而是选择专注于一个可互操作的then
方法。未来在配套规范中的工作可能会涉及这些主题。
1.术语
1.1
promise
是具有then
方法的对象或者函数,其行为符合规范。1.2
thenable
是定义在then
方法上的对象或者函数。1.3
value
是任何合法的JavaScript
值(包括undefined
,thenable
,或者promise
)1.4
exception
是使用抛出语句抛出的值1.5
reason
是一个表明promise
为什么失败的值
2.需求
2.1 Promise状态
2.1.1 当
promise
状态为pending
时:- 2.1.1.1 可以变为完成状态或者失败的状态
2.1.2 当
promise
状态为fulfilled
时:2.1.2.1 不能变为任何一种状态
2.1.2.2 必须有一个
value
,这个value
不能改变
2.1.3 当
promise
为rejected
时:2.1.3.1 不能变为任何一种状态
2.1.3.2 必须有一个
reason
,这个reason
不能改变
2.2 then方法
promise
必须提供一个then
方法,来访问它当前或最终的value
或reason
。
一个promise
的then
方法接收两个参数:
promise.then(onFulfilled, onRejected)
复制代码
2.2.1
onFulfilled
和onRejected
都是可选的参数2.2.1.1 如果
onFulfilled
不是函数,必须被忽略2.2.1.2 如果
onRejected
不是函数,必须被忽略
2.2.2 如果
onFulfilled
是一个函数2.2.2.1 它必须在
promise
完成后被调用,然后把promise
的值作为它的第一个参数2.2.2.2 它不能在
promise
完成前被调用。2.2.2.3 它不能被调用超过一次。
2.2.3 如果
onRejected
是一个函数2.2.3.1 它必须在
promise
失败后被调用,然后把promise
的值作为它的第一个参数2.2.3.2 它不能在
promise
失败前被调用。2.2.3.3 它不能被调用超过一次。
2.2.4 在执行上下文堆栈(execution context)仅包含平台代码之前,不得调用
onFulfilled
和onRejected
[3.1]2.2.5
onFulfilled
和onRejected
必须作为函数调用(即没有this
值)[3.2]2.2.6
then
方法可能在同一次promise
中被调用多次2.2.6.1 如果/当
promise
完成时,所有相应的onFulfilled
回调必须按照最原始的then
顺序来执行2.2.6.2 如果/当
promise
失败时,所有相应的onRejected
回调必须按照最原始的then
顺序来执行
2.2.7
then
方法必须返回一个promise
promise2 = promise1.then(onFulfilled, onRejected);
2.2.7.1 如果
onFulfilled
和onRejected
返回一个值x
,请运行Promise Resolution Procedure[[Resolve]](promise2, x)
2.2.7.2 如果
onFulfilled
和onRejected
抛出一个异常e
,promise2
必须拒绝并将e
作为reason
2.2.7.3 如果
onFulfilled
不是一个函数,且promise1
为完成状态,promise2
必须使用与promise1
相同的value
完成2.2.7.4 如果
onRejected
不是一个函数,且promise1
为失败状态,promise2
必须使用与promise1
相同的reason
完成
2.3 Promise解决程序
promise
解析过程是一个以输入promise
和value
的抽象操作,我们记作[[Resolve]](promise, x)
,如果x
是thenable
,假设x
的行为有点像promise
,它会尝试让promise
采用x
的状态。否则,它将使用x
值来完成promise
。
只要有实现Promises/A+
兼容的then
方法,对thenable
的处理允许使用promise
实现能够互操作。它还允许Promises/A+
实现使用合理的then
方法“同化”不一致的实现。
运行[[Resolve]](promise, x)
,执行以下的步骤:
2.3.1 如果
promise
和x
引用同一个对象,则用TypeError
作为reason
拒绝promise
2.3.2 如果
x
是一个promise
,则采用它的状态[3.4]2.3.2.1 如果
x
为pending
状态,promise
必须保持pending
状态直到x
成功或者失败2.3.2.2 如果
x
为完成状态,用相同的值完成promise
2.3.2.3 如果
x
为失败状态,用相同的reason
拒绝promise
2.3.3 如果
x
是一个对象或函数2.3.3.1 让
then
为x.then
[3.5]2.3.3.2 如果检索属性
x.then
的结果抛出一个异常e
,用e
作为reason
拒绝promise
2.3.3.3 如果
then
是一个函数,把x
作为this
调用它,第一个参数resolvePromise
和第二个参数rejectPromise
,其中:2.3.3.3.1 如果
resolvePromise
被y
值调用,运行[[Resolve]](promise, y)
2.3.3.3.2 如果
rejectPromise
被为r
的reason
调用,用r
来拒绝promise
2.3.3.3.3 如果
resolvePromise
和rejectPromise
都被调用,或者对同一个参数进行多次调用,则第一次调用优先,任何进一步的调用被忽略
2.3.3.4 如果
then
不是函数,用x
来完成promise
2.3.4 如果
x
不是对象或者函数,用x
来完成promise
如果使用参与循环的可循环链的可转换组件解决了一个promise
,这样,[[Resolve]](promise, thenable)
的递归性质导致了再次调用[[Resolve]](promise, thenable)
,遵循上述算法将导致无限递归。鼓励(但不是必须)实现来检测这种递归且用包含信息的TypeError
作为reason
拒绝promise
。[3.6]
3.笔记
3.1
这里的“平台代码”是指引擎,环境和promise
实现代码。在实践中,这个需求确保onFulfilled
和onRejected
异步执行,在事件循环之后调用then
,并且使用一个新栈。这可以通过setTimeout
或者setImmediate
宏任务机制,或者使用MutationObserver
或者process.nextTick
微任务机制来实现。由于promise
实现被视为平台代码,因此它本身可能包含一个任务调度队列或“蹦床”在其中调用处理程序。
3.2
也就是说,在严格模式下,this
为undefined
,在宽松模式中,它是一个全局对象(global object
)
3.3
在满足所有需求的情况下,可以允许实现promise2 === promise1
,每个实现都应该记录它是否能够产生promise2 === promise1
以及在何种条件下产生
3.4
通常,只有x
来自于当前实例时,才知道它是一个真正的promise
,此条款允许使用特定的实现方法来采用已知符合promise
的状态。
3.5
这个过程首先存储对x.then
的引用,然后测试,然后调用这个引用。避免了对x.then
属性的多次访问。这些预防措施对于确保访问者属性的一致性非常重要,因为访问者属性的值可能在两次检索之间发生变化。
3.6
实现不应该对thenable
链的深度设置任何限制,并假设递归超出限制。只有真正的循环才会导致TypeError
,如果遇到无穷多个thenable
链,那么永远递归是正确的行为。
总结
熟悉promise
规范有助于我们深刻理解promise
原理,为之后看源码,手写源码铺路~很久不碰英语了,很长时间之后第一次做翻译,如果有翻译不好的地方,还希望指出~我们共同学习,共同进步~
最后,分享一下我的公众号「web前端日记」,如果想更加及时的看见文章,马上就去关注哇😍