promises A+规范

Promises/A+

 

健全的、可互操作的 JavaScript 承诺的开放标准——由实施者提供,为实施者服务。

承诺代表异步操作的最终结果。 与承诺交互的主要方式是通过其 then 方法,该方法注册回调以接收承诺的最终值或承诺无法实现的原因。

该规范详细说明了 then 方法的行为,提供了一个可互操作的基础,所有符合 Promises/A+ 的承诺实现都可以依赖该基础来提供。 因此,规范应该被认为是非常稳定的。 尽管 Promises/A+ 组织可能偶尔会通过向后兼容的较小更改来修改此规范以解决新发现的极端情况,但我们只有在仔细考虑、讨论和测试后才会集成大的或向后不兼容的更改。

从历史上看,Promises/A+ 澄清了早期 Promises/A 提案的行为条款,将其扩展到涵盖事实上的行为,并省略了未指定或有问题的部分。

最后,核心 Promises/A+ 规范不涉及如何创建、履行或拒绝承诺,而是选择专注于提供可互操作的 then 方法。 伴随规范的未来工作可能会涉及这些主题。

术语

“promise”是具有 then 方法的对象或函数,其行为符合本规范。
“thenable”是定义 then 方法的对象或函数。
“value”是任何合法的 JavaScript 值(包括 undefined、thenable 或 promise)。
“异常”是使用 throw 语句抛出的值。
“reason”是一个值,表示承诺被拒绝的原因。

要求

承诺状态


承诺必须处于以下三种状态之一:待定、已完成或被拒绝。

  1. 当未决时,承诺:
    可以转换到已完成或拒绝状态。
  2. 实现时,承诺:
    不得过渡到任何其他状态。
    必须有一个不能改变的值。
  3. 当被拒绝时,一个承诺:
    不得过渡到任何其他状态。
    一定有理由,不能改变。

在这里,“不得改变”意味着不变的身份(即 ===),但并不意味着深刻的不变性。


Then 方法

承诺必须提供 then 方法来访问其当前或最终值或原因。

一个 promise 的 then 方法接受两个参数:

promise.then(onFulfilled, onRejected)

onFulfilled 和 onRejected 都是可选参数:

  1. 如果 onFulfilled 不是函数,则必须忽略它。
  2. 如果 onRejected 不是函数,则必须忽略它。

如果 onFulfilled 是一个函数:

  1. 必须在 promise 完成后调用它,promise 的值作为它的第一个参数。
  2. 在 promise 完成之前不能调用它。
  3. 它不能被多次调用。

如果 onRejected 是一个函数,

  1. 必须在 promise 被拒绝后调用它,promise 的原因作为它的第一个参数。
  2. 在 promise 被拒绝之前不能调用它。
  3. 它不能被多次调用。

在执行上下文堆栈仅包含平台代码之前,不得调用 onFulfilled 或 onRejected[3.1]。

onFulfilled 和 onRejected 必须作为函数调用(即没有这个值)[3.2]。

然后可以在同一个承诺上多次调用。

如果/当承诺被履行,所有相应的 onFulfilled 回调必须按照它们对 then 的原始调用的顺序执行。
如果/当承诺被拒绝时,所有相应的 onRejected 回调必须按照它们对 then 的原始调用的顺序执行。

然后必须返回一个承诺[3.3]。

promise2 = promise1.then(onFulfilled, onRejected);

如果 onFulfilled 或 onRejected 返回值 x,则运行 Promise Resolution Procedure [[Resolve]](promise2, x)。
如果 onFulfilled 或 onRejected 抛出异常 e,promise2 必须以 e 作为原因被拒绝。
如果 onFulfilled 不是函数并且 promise1 已实现,则 promise2 必须以与 promise1 相同的值实现。
如果 onRejected 不是函数并且 promise1 被拒绝,则 promise2 必须以与 promise1 相同的原因被拒绝。

承诺解决程序

承诺解析过程是一个抽象操作,将承诺和值作为输入,我们将其表示为 [[Resolve]](promise, x)。 如果 x 是一个 thenable,它会尝试让 promise 采用 x 的状态,假设 x 的行为至少有点像 promise。 否则,它以值 x 履行承诺。

对 thenables 的这种处理允许 promise 实现互操作,只要它们公开一个符合 Promises/A+ 的 then 方法。 它还允许 Promises/A+ 实现使用合理的 then 方法“同化”不一致的实现。

要运行 [[Resolve]](promise, x),请执行以下步骤:

  1. 如果 promise 和 x 引用同一个对象,则以 TypeError 作为原因拒绝 promise。
  2. 如果 x 是一个承诺,采用它的状态[3.4]:
    • 如果 x 是挂起的,promise 必须保持挂起直到 x 被完成或拒绝。
    • 如果/当 x 完成时,用相同的值完成承诺。
    • 如果/当 x 被拒绝时,以同样的理由拒绝承诺。
  3. 否则,如果 x 是一个对象或函数,
    • 设那么为 x.then。 [3.5]
    • 如果检索属性 x.then 导致抛出异常 e,则以 e 为原因拒绝 promise。
    • 如果 then 是一个函数,则使用 x 作为 this 调用它,第一个参数是 resolvePromise,第二个参数是 rejectPromise,其中:
      • 如果/当使用值 y 调用 resolvePromise 时,运行 [[Resolve]](promise, y)。
      • 如果/当以 r 的原因调用 rejectPromise 时,用 r 拒绝 promise。
      • 如果同时调用了 resolvePromise 和 rejectPromise,或者对同一个参数进行了多次调用,则第一个调用优先,任何进一步的调用都将被忽略。
      • 如果调用则抛出异常 e
        • 如果调用了 resolvePromise 或 rejectPromise ,则忽略它。
        • 否则,以 e 为理由拒绝 promise。
      • 如果 then 不是函数,则用 x 实现 promise。
  4. 如果 x 不是对象或函数,则用 x 实现 promise。

如果一个 promise 是用参与循环 thenable 链的 thenable 解析的,这样 [[Resolve]](promise, thenable) 的递归性质最终会导致 [[Resolve]](promise, thenable) 再次被调用,如下 上述算法会导致无限递归。 鼓励但不要求实现以检测此类递归并拒绝以信息丰富的 TypeError 作为原因的承诺。[3.6]

笔记

  1. 这里的“平台代码”是指引擎、环境和promise实现代码。 在实践中,这个要求确保 onFulfilled 和 onRejected 异步执行,在调用 then 的事件循环之后,并使用新的堆栈。 这可以通过“宏任务”机制(例如 setTimeout 或 setImmediate)或“微任务”机制(例如 MutationObserver 或 process.nextTick)来实现。 由于promise实现被认为是平台代码,它本身可能包含一个任务调度队列或“trampoline”,在其中调用处理程序。
  2. 也就是说,在严格模式下,这在它们内部是未定义的; 在草率模式下,它将是全局对象。
  3. 实现可以允许 promise2 === promise1,前提是实现满足所有要求。 每个实现都应该记录它是否可以产生 promise2 === promise1 以及在什么条件下。
  4. 通常,只有当 x 来自当前实现时,才会知道 x 是一个真正的承诺。 该条款允许使用特定于实现的手段来采用已知符合承诺的状态。
  5. 这个首先存储对 x.then 的引用,然后测试该引用,然后调用该引用的过程避免了对 x.then 属性的多次访问。 这些预防措施对于确保访问器属性的一致性很重要,访问器属性的值可能会在检索之间发生变化。
  6. 实现不应对 thenable 链的深度设置任意限制,并假设超出该任意限制递归将是无限的。 只有真正的循环才会导致 TypeError; 如果遇到无限的不同 thenable 链,则永远递归是正确的行为。

最后

原文是【PromisesA+规范】

 

posted @ 2021-12-03 11:31  只做你的向日葵  阅读(71)  评论(0)    收藏  举报