Promises/A+ 标准翻译 & 学习
原文翻译 & 学习正文
原文链接
1. 术语
1.1 “promise” 是一个领有 then 办法的函数或者对象,它的行为合乎本标准。
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 状态时,promise:
2.1.1.1 可能转换为 fulfilled 状态或者 rejected 状态。
2.1.2 当处于 fulfilled 状态时,promise:
2.1.2.1 不能转换为其余状态。
2.1.2.2. 必须有一个 value,该 value 不可被扭转。
2.1.3 当处于 rejected 状态时,promise:
2.1.3.1 不能转换为其余状态。
2.1.3.2. 必须有一个 reason,该 reason 不可被扭转。
在此,“不可被扭转”意味着不变的特色(即 ===),然而并不示意 “deep immutability”。
“deep immutability” 相似于 const 作用于援用类型时的状况:
const arr = [1];
arr = [2]; // Uncaught TypeError: Assignment to constant variable.
arr[0] = 2;
console.log(arr); // [2]
promise 举例:
var value = [1];
var p = Promise.resolve(value);
p.then(a => console.log(a)); // [1]
p.then(a => console.log(a === value)); // true
// 对 value 援用的批改仅在以后 then 函数的块级作用域内无效。p.then(a => { a = [2]; console.log(a);}); // [2]
p.then(a => console.log(a)); // [1]
// 能够批改 value 中每一项的值。p.then(a => { a[0] = 2; console.log(a);}); // [2]
p.then(a => console.log(a)); // [2]
p.then(a => console.log(a === value)); // true
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 在执行上下文堆栈仅包含 ”platform code” 之前不得被调用。(”platform code” 指的是引擎、环境以及 promise 的实现代码。实际上,这一要求确保 onFulfilled 和 onRejected 异步执行,并且在事件循环完结后返回到 then 函数被调用的中央,从新应用新的堆栈。这能够通过宏工作机制(例如 setTimeout 或者 setImmediate)或微工作机制(例如 MutationObserver 或者 process.nextTick)实现。因为 promise 的实现被看做 platform code,它可能本身蕴含一个任务调度队列或者“蹦床”,在其中调用处理程序)。
2.2.5 onFulfilled 和 onRejected 该当被作为函数调用(即没有 this 值)。
这里的没有 this 值指的是,在 strict 模式下,this 值为 undefined,在 sloppy 模式下,this 值为全局对象。
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。
如果代码实现满足了所有的要求,那么该当容许 promise2 === promise1。每一个实现须要文档记录它是否容许 promise2 === promise1 以及在什么条件下才容许这种后果。
promise2 = promise1.then(onFulfilled, onRejected);
2.2.7.1 如果 onFulfilled 或者 onRejected 返回值 x, 容许 Promise 解析流程 [[Resolve]](promise2, x).
2.2.7.2 如果 onFulfilled 或者 onRejected 抛出异样 e, 则 promise2 必须处于 rejected 状态,reason 是 e。
2.2.7.3 如果 onFulfilled 不是一个函数并且 promise1 处于 fulfilled 状态,promise2 必须是 fulfilled 状态,并且 value 和 promise1 雷同。
2.2.7.4 如果 onRejected 不是一个函数并且 promise1 处于 rejected 状态, promise2 必须是 rejected 状态,并且 reason 和 promise1 雷同。
2.3 Promise 解析流程
promise 解析过程是以一个 promise 和一个 value 作为输出参数的形象操作,咱们将其示意为 [[Resolve]](promise, x)。如果 x 是一个 thenable,它试图使 promise 采纳 x 的状态,前提是 x 的行为至多有点像 promise。否则,应用值 x 执行 promise。
这种对 thenable 的解决容许 promise 实现交互操作,只有它们裸露合乎 Promises/A+ 标准的 then 办法。它还容许 Promises/A+ 标准实现用正当的 then 办法“异化”不符合要求的实现。
要运行 [[Resolve]](promise, x),请执行接下来的步骤:
2.3.1 如果 promise 和 x 指向同样的对象,应用 TypeError 作为 reason 回绝该 promise。
2.3.2 如果 x 是一个 promise, 驳回它的状态(通常来说,只有当 x 来自以后的实现时,才能够确定 x 是一个真正的 promise。本条款容许应用特定的施行办法来采纳合乎已知标准的 promise 的状态):
2.3.2.1 如果 x 处于 pending 状态, promise 必须放弃 pending 状态直到 x 变为 fulfilled 状态或者 rejected 状态.
2.3.2.2 如果 x 处于 fulfilled 状态, 用与 x 雷同的 value 值执行该 promise。
2.3.2.3 如果 x 处于 rejected 状态, 用与 x 雷同的 reason 值回绝该 promise。
2.3.3 否则,如果 x 是一个对象或者函数,
2.3.3.1 将 x.then 赋值给 then(首先存储对 x.then 的援用,而后测试该援用,之后调用该援用。这个过程防止了对 x.then 属性的屡次拜访。这些预防措施对于确保拜访器属性的一致性十分重要,因为拜访器属性的值在两次检索之间可能会发生变化):
2.3.3.2 如果检索属性 x.then 导致抛出了一个异样 e,应用 e 作为 reason 回绝该 promise。
2.3.3.3 如果 then 是一个函数,将 x 作为 then 函数的 this,第一个参数叫 resolvePromise,第二个参数叫 rejectPromise:
2.3.3.3.1 如果 resolvePromise 以值 y 为参数被调用,运行[[Resolve]](promise, y)。
2.3.3.3.2 如果 rejectPromise 以 reason r 为参数被调用,应用 r 回绝该 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 回绝该 promise。
2.3.3.4 如果 then 不是一个函数,应用 x 执行该 promise。
2.3.4 如果 x 不是对象或者函数,应用 x 执行该 promise。
如果一个 promise 被一个处于 thenable 循环链中的 thenable 解决(例如[[Resolve]](promise, thenable) 的递归性质导致其本身再次被调用),遵循上述的算法会导致有限递归。(咱们)激励(但不是要求)实现检测这种递归,并以信息拼写错误作为 reason 回绝 promise(实现不应该对 thenable 链的深度设置任意大小的限度,并且假设超过该限度的递归将会是有限的。只有真正的循环应该导致 TypeError,如果碰巧遇见了一个蕴含不同 thenable 的有限链,那么永远递归是正确的行为)。
参考资料
- Promises/A+
- Promise 源码学习】第四篇 – 翻译并了解 Promise A+ 标准
- What is deep immutability?