引言
俗话说好记性不如烂笔头,所以我决定翻译一下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方法必须返回一个promisepromise2 = 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作为reason2.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拒绝promise2.3.2 如果
x是一个promise,则采用它的状态[3.4]2.3.2.1 如果
x为pending状态,promise必须保持pending状态直到x成功或者失败2.3.2.2 如果
x为完成状态,用相同的值完成promise2.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拒绝promise2.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来拒绝promise2.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前端日记」,如果想更加及时的看见文章,马上就去关注哇😍
