原文: Promise/A+
描述
promise 表示异步操作的最终结果。与promise交互的主要方式是通过它的 then 方法,该方法注册回调以接收promise的最终value,或者为什么 promise 无法 fulfilled 的原因。
该规范详细说明了 then 方法的行为,提供了一个互操作的基础,所有符合 Promises/A+ 的 promise 实现都可以依赖该基础。尽管 promise/A+ 组织可能偶尔会用小的向后兼容的更改来修改此规范,以解决新发现的边缘情况,但只有在仔细考虑、讨论和测试之后,我们才会集成大的或向后不兼容的更改。因此,该规范应该被认为是非常稳定的。
从历史上看,promise/A+ 澄清了早期 Promises/A proposal,将其扩展到涵盖事实上的行为,并省略了不明确或有问题的部分。
最后,核心promise/a规范并没有处理如何create 、fulfill 或 reject promises,而是选择专注于提供可互操作的 then 方法。未来在配套规范方面的工作可能会涉及到这些主题。
专业术语
1.1 "prmoise" 是一个拥有符合本规范的 then 方法的对象或者函数。
1.2 "thenable" 是一个定义了 then 方法的对象或者函数。
1.3 "value" 是 JavaScript 的任意合法值(包括 undefined, thenable, promise)。
1.4 "exception" 是一个通过 throw 语句抛出的 value 。
1.5 "reason" 是一个表示 promise 为什么被 rejected 的 value 。
要求
2.1 Promise 的状态
一个 promise 必须在三种状态之一: pending, fulfilled, rejected
2.1.1 当 promise 处于 pending 状态:
2.1.1.1 可以转换到 fulfilled 或 rejected 状态
2.1.2 当 promise 处于 fulfilled 状态:
2.1.2.1 不能转换到其他状态
2.1.2.2 必须有一个不能改变的 value
2.1.3 当 promise 处于 rejected 状态:
2.1.3.1 不能转换到其他状态
2.1.3.2 必须有一个不能改变的 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 状态为 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 在 execution context 栈(执行上下文栈)只包含平台代码之前,onFulfilled or onRejected 不能被调用 [3.1].
2.2.5 onFulfilled 或 onRejected 必须以函数形式调用(即不能有this值)[3.2]
2.2.6 then 方法可以被同一个 promise 调用多次
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 必须以e作为 reason ,转到 rejected 状态。
2.2.7.3 如果 onFulfilled 不是函数,并且 promise1 处于 fulfilled 状态 ,则 promise2 必须以与 promise1 同样的 value 被 fulfilled
2.2.7.4 如果 onRejected 不是函数,并且 promise1 处于 rejected 状态 ,则 promise2 必须以与 promise1 同样的 reason 被 rejected
2.3 The Promise Resolution Procedure
Promise Resolution Procedure 是一种抽象操作。以 promise 和 value 作为输入,记作:[[Resolve]](promise, x)。 如果 x 是一个 thenable , 它会尝试让 promise 变成与 x 一样状态 ,前提 x 是一个类似 promise 对象。否则,它会让 promise 以 x 作为 value 转为 fulfilled 状态。
这种对 thenables 的处理允许不同的 promise 进行互操作,只要它们暴露一个符合 Promises/A+ 的 then 方法。它还允许 Promises/A+ 实现使用合理的 then 方法“同化”不一致的实现。
[[Resolve]](promise, x) 执行步骤如下:
2.3.1 如果 promise 和 x 引用的同一个对象,则以一个 TypeError 作为 reason 让 promise 转为 rejeted 状态。
2.3.2 如果 x 是一个promise,则采用 promise 的状态[3.4]
2.3.2.1 如果 x 处于 pending 状态,promise 必须保持 pending 状态, 直到 x 变成 fulfilled 或者 rejected 状态, promise 才同步改变
2.3.2.2 如果 x 处于 fulfilled 状态, 以同样的 value 让 promise 也变成 fulfilled 状态。
2.3.2.3 如果 x 处于 rejected 状态, 以同样的 reason 让 promise 也变成 rejected 状态。
2.3.3 如果 x 是一个对象或函数
2.3.3.1 让 then 等于 x.then [3.5]
2.3.3.2 如果 x.then 抛出异常e, 以e作为 reason 让 promise 变成 rejected 状态
2.3.3.3 如果 then 是一个函数,以 x 作为 this 调用它,传入第一个参数 resolvePromise, 第二个参数 rejectPromise
2.3.3.3.1 如果 resolvePromise 被传入 y 调用, 则执行 [[Resolve]](promise, y)
2.3.3.3.2 如果 rejectedPromise 被传入 r 调用,则用 r 作为 reason 让 promise 变成 rejected 状态
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 变成 rejected 状态
2.3.3.4 如果 then 不是一个函数,以 x 作为 value 让 promise 变成 fulfilled 状态
2.3.4 如果 x 不是对象或函数, 以 x 作为 value 让 promise 变成 fulfilled 状态
如果一个 promise 用参与循环 thenable 链的 thenable 来解析, 而 [[Resolve]](promise, thenable) 的递归性质又使得其被再次调用,根据上述的算法将会陷入无限递归之中。算法虽不强制要求,但也鼓励实现者检测这样的递归是否存在,并且以 TypeError 作为 reason 拒绝 promise[3.6]
注释
3.1 这里的平台代码指的是引擎、环境以及 promise 的实现代码。 在实现中,要确保在 onFulfilled和 onRejected 的事件循环打开之后异步执行,并使用一个新的堆栈。这可以通过macro-task机制来实现,如setTimeout或setImmediate,也可以通过micro-task机制,如MutationObserver或process.nextTick来实现。由于promise实现被认为是平台代码,因此它本身可能包含一个任务调度队列或trampoline,其中调用了处理程序。
3.2 在严格模式中,函数 this 的值为 undefined; 在非严格模式中其为全局对象。
3.3 实现可能允许 promise2 === promise1,前提是实现满足所有要求。每个实现都应该记录它是否可以产生 promise2 === promise1,以及在什么条件下。
3.4 通常,如果 x 来自当前的实现,才能知道 x 是一个真正的promise。该条款允许使用特定于实现的方法来采用已知的符合promise的状态。
3.5 首先存储了一个指向 x.then 的引用,然后测试并调用该引用,以避免多次访问 x.then 属性。这种预防措施确保了该属性的一致性,因为其值可能在检索调用时被改变
3.6 实现不应该对可thenable链的深度设置任意的限制,并假设超过这个任意限制后,递归将是无限的。只有真正的循环才会导致TypeError; 如果遇到了无限个不同的thenable,那么永远递归是正确的行为。