如题,本文为最新的promise/A+规范的中文翻译,格式和原文保持一致,如有错误,欢迎指正。
一个健全的、可互操作的 JavaScript 的开放标准,由开发者制定,供开发者参考。
promise
表示异步操作的最终结果。与promise
交互的主要方式是通过其then
方法,该方法注册回调以接收promise
的最终值或promise
无法实现的原因。
本规范详细说明了then
方法的行为,提供了一个可互操作的基础,所有符合Promises/A+
的promise
实现都可以依赖于该基础来提供。因此,该规范应被视为非常稳定。尽管Promises/A+
组织可能偶尔会通过较小的向后兼容更改来修改本规范,以解决新发现的极端情况,但只有经过仔细考虑、讨论和测试,我们才会集成较大或向后不兼容的更改。
结合之前的规范来看,Promises/A+
澄清了早期 Promises/A 提案的行为条款,并进行了具体的实现,同时省略了未明确说明或有问题的部分。
最后强调一下,核心 Promises/A+
规范不涉及如何创建、调用和执行,而是选择专注于提供通用的 then
方法规范指南。上述对于 promises
的操作方法将来在其他规范中可能会提及。
1. 专业术语
1.1 promise
: 一个包含then
方法的对象或者函数,只要符合这个规范的均可以称为promise
。
1.2 thenable
: 一个内部定义了then
方法的对象或者函数。
1.3 value
: 是任何javascript的合法值(包括 undefined
,thenable
, promise
)。
1.4 exception
: 使用throw
语句抛出的值。
1.5 reason
: 表示当前promise
被拒绝的原因。
2. 要求
2.1 Promise 状态
任何一个promise
的状态必须以下三种状态的一种:pending
, fulfilled
, rejected
.以下是三者的详细要求:
2.1.1 pending
状态:
2.1.1.1 promise
的可以被转变为fulfilled
和 rejected
的任何一个状态
2.1.2 fulfilled
状态:
2.1.2.1 此时promise
的状态不能再被改变。
2.1.2.2 promise
有一个结果值,但是也不能再被改变。
2.1.3 rejected
状态:
2.1.3.1 此时promise
的状态不能再被改变。
2.1.3.2 promise
有一个被拒绝的原因,同时也不能再被改变。
这里声明一下:不能被改变 指的是身份不能被改变,判断逻辑是使用javascript的===
进行比较,但是不意味着深度不可被改变(这里可以参考const类型数据的的更改,非引用类型的值不能被修改,但是引用类型的是可以修改数据的属性,只是不能对目标直接执行赋值操作,推测应该是目标的的内存地址不可变)
2.2 then
方法
promise
必须提供一个then
方法来获取它当前或者最终的值或者被拒绝的理由。promise
的then
方法接收两个参数,其语法如下:
javascript
promise.then(onFulfilled, onRejected)
以下是关于参数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
状态切换为 fulfilled
时被调用,同时promise
的value
作为它的第一个参数。
2.2.2.2 它一定不能在当前promise
的状态切换为 fulfilled
之前被调用。
2.2.2.3 它只能被调用一次
2.2.3 如果 onRejected
是一个函数
2.2.3.1 它一定会在当前promise
状态切换为 rejected
时被调用,同时promise
的reason
作为它的第一个参数。
2.2.3.2 它一定不能在当前promise
的状态切换为 rejected
之前被调用。
2.2.3.3 它只能被调用一次
2.2.4 onFulfilled
和 onRejected
只有在执行上下文堆栈仅包含平台代码 时才可被调用。[3.1]
2.2.5 onFulfilled
和 onRejected
必须作为函数进行调用(即没有this
值)[3.2]
2.2.6 then
可能会在同一个promise
上多次进行调用
2.2.6.1 如果promise
的状态是已完成,所有的相应的 onFulfilled
回调都必须按照调用的顺序执行。
2.2.6.2 如果promise
的状态是拒绝状态,所有的相应的 onRejected
回调都必须按照调用的顺序执行。
2.2.7 then
必须返回一个promise
[3.3],如下:
javascript
promise2 = promise1.then(onFulfilled, onRejected);
2.2.7.1 如果 onFulfilled
或 onRejected
返回值一个值 x
,则运行Promise
解析过程 [[Resolve]](promise2, x)。
2.2.7.2 如果 onFulfilled
或者 onRejected
抛出异常 e
,则 promise2
必须以e
作为reason
将promise2
置为rejected
2.2.7.3 如果 onFulfilled
不是函数且 promise1
成功执行, promise2
必须和promise1
一样的value
将状态置为 fulfilled
2.2.7.4 如果 onRejected
不是函数且 promise1
拒绝执行, promise2
必须拒绝执行并返回和promise1
相同的reason
2.3 Promise的解决过程
promise
解决过程是一个抽象操作,将promise
和值作为输入,我们将其表示为[[Resolve]](promise,x)
。如果x
是thenable
,这种情况下,可以把x
看作是一个promise
,此时试图使promise
采用x
的状态。否则,它将用x
作为value
来完成promise
。
这种对thenables
的处理允许promise
实现更加通用:只要它们对外暴露了符合Promises/a+
的then
方法即可。它还允许Promises/A+
实现用合理的方法"兼容"不一致的实现。
运行 [[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
必须在 x
被执行和被拒绝之前保持pending
状态。
2.3.2.2 如果x
的状态是 fulfilled
, 则使用相同的value
执行promise
.
2.3.2.3 如果x
的状态是rejected
,则使用相同的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
进行调用(可以理解为:x.then().bind(x))
,同时它的第一个参数 是resolvePromise
, 第二个参数是 rejectPromise
,关于这两个参数:
2.3.3.3.1 如果使用value
y
调用resolvePromise
,则运行[[Resolve]](promise, y)
.
2.3.3.3.2 如果使用reason
r
调用 rejectPromise
,则使用r
作为reason
拒绝promise
。
2.3.3.3.3 如果 resolvePromise
和 rejectPromise
都被调用,或者使用同一参数调用了多次,则优先采用第一次调用并且忽略其他所有后续的调用.
2.3.3.3.4 如果调用 then
方法出现了一个异常 e
:
2.3.3.3.4.1 如果 resolvePromise
和 rejectPromise
已经被调用,则忽略这个异常.
2.3.3.3.4.2 否则 将上述的e
作为 reason
拒绝promise
.
2.3.3.4 如果 then
不是一个函数,则直接使用x
作为value
来实现promise
.
2.3.4 如果x
不是一个对象或者函数,则直接使用x
作为value
来实现promise
.
如果一个promise
被一个循环的thenable
链中的thenable
来解析,由于[[Resolve]](promise,thenable)
的递归性质最终导致[[Resolve]](prome,thenabe)
被再次调用,遵循上述算法将导致无限递归。我们鼓励但不强制要求开发者去检测这种递归,并以提供能够可识别的TypeError
作为reason
拒绝 promise
。[3.6]
3.注释
3.1
这里的"平台代码"是指引擎、环境和promise
实现代码。在实践中,这一要求确保onFulfilled
和onRejected
在调用事件循环之后异步执行,并使用新的堆栈。这可以用"宏任务"机制(如setTimeout
或setImmediate
)实现,也可以用"微任务"机制,如MutationObserver
或process.nextTick
实现。由于promise
实现被视为平台代码,它本身可能包含一个任务调度队列或"蹦床",在其中调用处理程序。
3.2
也就是说,在严格模式下,这在它们内部是 undefined
;在非严格模式下,它将是全局对象。
3.3
实现可以允许promise2===promise1
,前提是实现满足所有要求。每个实现都应该记录它是否可以生成promise2===promise1
以及在什么条件下生成。
3.4
一般来说,只有当x
来自当前实现时,才能确认它是一个真正的 promise
。该条款允许使用特定于实现的手段来采用已知一致承诺的状态。
3.5
这个过程首先存储对x.then
的引用,然后测试该引用,然后调用该引用,避免了对x.then
属性的多次访问。这些预防措施对于确保访问者属性的一致性非常重要,因为访问者属性的值可能在不同的检索之间发生变化。
3.6
实现不应对可用链的深度设置任意限制,并假设超过该任意限制,递归将是无限的。只有真正的循环才会导致TypeError
;如果遇到一个由不同的二进制数组成的无限链,则永远的递归下去是正确的行为。