Promises/A+
为实现者提供一个健全的、可互操作的 JavaScript promise 的开放标准。
一个 promise 代表了一个异步操作的最终结果。与一个 promise 交互的主要方式是通过它的 then 方法向 promise 注册回调函数(callbacks),回调函数则用来接收 promise 的的最终值(eventual value)或者promise失败(cannot be fulfilled)的原因。
本规范(specification )详细描述了 then
方法的行为,提供了一个可互操作(interoperable)的基础,所有与Promises/A+ 规范一致的promise实现, 都可以依赖于这个基础。因此,规范应该被认为是非常稳定的。尽管Promises/A+组织可能偶尔会进行小的且向后兼容的更改去修改(revise)此规范,以解决新发现的极端案例(corner cases),但只有在仔细考虑、讨论和测试之后,我们才会集成大的或向后不兼容的更改。
从历史上看,Promises/A+阐述了早起 Promises/A proposal的行为条款,将其扩展以覆盖实际(de facto)行为,并删除了不明确或有问题的部分。
最后,Promises/A+规范核心不解决如何create、fulfill或reject promise,取而代之是选择提供一个可互操作的then
方法。未来有关配套规范的工作可能涉及到这些主题。
1. 术语
1.1. “promise”是一个具有then方法的对象或函数,其行为符合本规范。
1.2. “thenable”是一个定义了then方法的对象或函数。
1.3. “value”是任何合法的javascript值(包括undefined
, a thenable
, or a promise
)。
1.4. “exception”是一个使用throw
语句抛出异常的值。。
1.5. “reason”是一个表明promise
被rejected原因的值。
2. 要求
2.1 Promise状态
一个promise
必须处于以下三种状态之一:pending,fulfilled 或 rejected。
2.1.1. 当处于 pending 状态时,a promise:
2.1.1.1. 即可以转换为 fulfilled 状态, 也可以转换 rejected 状态。
2.1.2. 当处于 fulfilled 状态时,a promise:
2.1.2.1. 一定不得转换到任何其他状态。
2.1.2.2. 必须有一个 value,且值不可变。
2.1.3. 当处于 rejected 状态时,a promise:
2.1.3.1. 一定不得转换到任何其他状态。
2.1.3.2. 必须有一个 reason ,且值不可变。
这里,“值不可变”是指不变恒等式(immutable identity)(如: ===),但并不意味着深层不变。
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
变为 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
直到执行上下文(execution context)堆栈只包含平台代码时才可以被调用。[3.1]。
2.2.5. onFulfilled
和 onRejected
必须以函数方式被调用,且没有this值(译者注: 以函数方式调用是指onFulfilled(v)这种方式,不可用 new onFulfilled() 方式或 onFulfilled.call() / onFulfilled.apply() 方式)。[3.2]
2.2.6. 在同一个promise上 then
方法可以多次被调用 。
2.2.6.1. 如果/当 promise
变为或已处于 fulfilled 时,各自的 onFulfilled
回调必须以其在 then 中注册顺序来执行。
2.2.6.2. 如果/当 promise
变为或已处于 rejected 时,各自的 onRejected
回调必须以其在 then 中注册顺序来执行。
2.2.7. then
方法必须返回一个promise。 [3.3].
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 必须被rejected,且以 e 作为reason。
2.2.7.3. 如果 onFulfilled
不是函数且 promise1 是 onFulfilled 状态,则 promise2 必须被Fulfilled, 且和promise1有同一个value。
2.2.7.4. 如果 onRejected
不是函数且 promise1 已处于 rejected 状态,则 promise2 必须 被 rejected, 且和promise1有同的 reason。
2.3 Promise决议程序(Resolution Procedure)
Promise Resolution Procedure 是以一个promise
和value
为参数的抽象操作,我们将其表示为 [[Resolve]](promise, x)
。如果 x 是一个 thenable
, 前提是x的行为至少有点像promise时,Promise Resolution Procedure 会试图让 promise 采用 x 的 state。与此不同,promise 会被Promise Resolution Procedure以 x 为值 fulfilled。
对 thenable
的这种处理允许promise
实现相互操作,只要它们公开了一个暴露了符合Promises/A+规范 的 then 方法即可。这种方式也使得遵循 Promises/A+规范 的实现可以“同化”那些没有遵循 Promises/A+规范 但具备合理的 then 方法的promise实现。
它还允许Promises/A+实现使用合理的II方法“同化”不合格的实现。
执行 [[Resolve]](promise, x) 需运行以下步骤:
2.3.1. 如果 promise 和 x 指向同一个对象,则 reject promise 并且以 TypeError 作为 reason。
2.3.2. 如果 x 是一个promise,则采用 x 的状态 [3.4]:
2.3.2.1. 如果 x 处于 pending 状态,则 promise 必须保持 pending 状态直到 x 被 fulfilled 或 rejected。
2.3.2.2. 当 x 状态是 fulfilled 时,用相同的 value 来 fulfill promise。
2.3.2.3. 当 x 状态是 rejected 时,用相同的 reason 来 reject promise。
2.3.3. 如果 x 是一个对象或函数,
2.3.3.1. 令 then 指向 x.then。[3.5]
2.3.3.2. 如果x.then导致抛出异常 e,则以 e 为 reason 来 reject promise。
2.3.3.3. 如果 then 是一个函数,则x.then
调用它,,以 resolvePromise 作为第一个参数,以 rejectPromise 作为第二个参数,情况如下:
2.3.3.3.1. 如果/当 resolvePromise被调用, 且value是 y,则执行 [[Resolve]](promise, y)。
2.3.3.3.2. 如果/当 rejectPromise 被调用了且value是 r,则以 r 来 reject promise。
2.3.3.3.3. 如果 resolvePromise 和 rejectPromise 都被调用了,或者以相同参数被调用多次,则第一次调用优先(precedence),其余相关调用忽略。
2.3.3.3.4. 如果调用 then 抛出异常 e:
2.3.3.3.4.1 如果 resolvePromise 或 rejectPromise 已经被调用过了,则忽略这个异常。
2.3.3.3.4.2 否则,reject promise, 且reason是e。
2.3.3.4. 如果 then 不是函数, fulfill promise, 且value是x。
2.3.4. 如果 x 既不是对象也不是函数,则fulfill promise, 且value是x。
如果一个promise被一个 thenable 决议,且此 thenable 在一个循环的thenable链中,[[Resolve]](promise, thenable) 的递归特性会导致 [[Resolve]](promise, thenable) 再次被调用,根据上面的算法,这会导致无限递归。因此我们鼓励(但不强制要求)promise实现时能检测无限递归,并在出现无限递归时以一个 TypeError 来 reject promise。
3. 说明
3.1. 这里的“平台代码(platform code)”意为引擎、环境和实现promise的代码。在实践中,这个需求确保了onFulfilled and onRejected的异步执行,在调用事件循环之后,使用一个新的堆栈。这可以通过“宏任务”机制(如settimeout或setimmediate)或“微任务”机制(如mutationobserver或process.nextick)来实现。由于Promise实现被视为平台代码,因此它本身可能包含一个任务调度队列或“蹦床”,在其中调用处理程序。
3.2. 这里指的是在 严格模式(strict mode) 下,this 在 onFulfilled 和 onRejected 中值为 undefined;在 非严格模式 下,this 指向全局对象(global object)。
3.3.实现可以允许promise2==promise1,前提是实现满足所有要求。每个实现都应该形成文档, 它是否能够生成promise2==promise1以及在什么条件下。
3.4. 一般来说,只有当 x
来自当前的实例时,才知道它是一个真正的 promise
。本条款允许使用特定于实现的方法来采用已知一致promise
的状态。
3.5. 先存储x.then 的引用,然后测试此引用,再然后调用此引用的过程,避免了对 x.then 属性的多次访问。这些预防措施对于确保访问器属性的一致性非常重要,访问器属性的值可能在两次检索之间发生更改。
3.6. 实现不应该对 thenable
的深度设置任意限制,并且假定超过该任意限制,递归将是无限的。只有真正的循环才能导致类型错误;如果遇到无限多个不同的 thenable
,则永远递归是正确的行为。
https://promisesaplus.com/