阅读 377

Promises/A+中文翻译

实现者为实施者提供开放的标准,实现可靠,可互操作的JavaScript Promise.

Promise表示异步操作的最终结果。与promise进行交互的主要方式是通过其then方法,该方法注册回调以接收promise的最终值或无法履行promise的原因。

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

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

最后,核心Promises/A+规范没有涉及如何创建,实现或拒绝Promise,而是选择专注于提供可互操作的then方法。配套规范中的未来工作可能涉及这些主题。

1.术语

  • 1.1. “promise”是具有then方法的对象或函数,其行为符合本规范。
  • 1.2. “thenable”是定义then方法的对象或函数。(promise是thenable对象)
  • 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),绝不能改变。
2.1.3. rejected状态时,Promise:
  • 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. 这两个onFulfilledonRejected可选的参数:
  • 2.2.1.1. 如果onFulfilled不是函数,则必须忽略它。
  • 2.2.1.2. 如果onRejected不是函数,则必须忽略它。
2.2.2. 如果onFulfilled是一个函数:
  • 2.2.2.1. 它必须在promise完成后调用,promise的value作为第一个参数。
  • 2.2.2.2. 在promise完成之前不得调用它。
  • 2.2.2.3. 它不能被多次调用。
2.2.3. 如果onRejected是一个函数:
  • 2.2.3.1. 它必须在promise被拒绝后被调用,promise的reason作为第一个参数。
  • 2.2.3.2. promise拒绝之前不得调用它。
  • 2.2.3.3. 它不能被多次调用。
2.2.4. onFulfilled或者onRejected执行上下文堆栈仅包含平台代码之前不得调用。(链式调用,then方法返回一个新的promise对象,需要等新promise对象实例化结束后才能调用then的回调函数) 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.如果任一onFulfilledonRejected返回一个值x(x可能是promise,所以需要增加处理函数),运行Promise解决程序[[Resolve]](promise2, x)
  • 2.2.7.2.如果onFulfilled或者onRejected抛出异常e,将e作为promise2rejected的reason。
  • 2.2.7.3.如果onFulfilled不是一个函数并且promise1已经完成,则promise2必须使用与promise1相同的value来fulfilled。
  • 2.2.7.4.如果onRejected不是一个函数而promise1被拒绝,promise2必须与promise1以同样的reason来rejected。

2.3.Promise解决程序

promise解决程序是一个函数,参数为一个promise和一个value,它表示为[[Resolve]](promise,x)。如果x是一个thenable(promise),它会尝试promise采用x的状态,前提是x行为至少有点像promise。否则,它作为promise的fulfilled的value返回。

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

要运行[[Resolve]](promise, x),请执行以下步骤:
2.3.1.如果promisex引用同一个对象,请以promise TypeError为reason来rejected。
2.3.2. 如果xpromise,采用其状态 3.4
  • 2.3.2.1. 如果x待处理pending,则promise必须保持待处理状态,直到xfulfilled或rejected为止。
  • 2.3.1.2. 如果/当 x fulfilled,则promise使用相同的value fulfilled。
  • 2.3.1.3. 如果/当 x rejected,请promise以同样的reason rejected。
2.3.3.否则,如果x是对象或函数:
  • 2.3.3.1.让then = x.then 3.5
  • 2.3.3.2.如果检索属性x.then中抛出的异常的结果e,将e作为 promise的reason来rejected。
  • 2.3.3.3.如果then是函数,将x作为this调用它,第一个参数resolvePromise和第二个参数rejectPromise,其中:
    • 2.3.3.3.1. 如果resolvePromise被调用并返回一个值y(原理同x,可能为promise),则运行[[Resolve]](promise, y)
    • 2.3.3.3.2. 如果/当 rejectPromise被调用并是带一个reasonr,将r作为拒绝promise的reason。
    • 2.3.3.3.3. 如果这两个resolvePromiserejectPromise被调用,或多次调用相同的参数,则第一次调用优先,任何进一步的调用将被忽略。
    • 2.3.3.3.4.如果调用then抛出异常e:
      • 2.3.3.3.4.1. 如果resolvePromiserejectPromise已被调用,请忽略它。
      • 2.3.3.3.4.2. 否则,将e作为promise的rejected的reason。
  • 2.3.3.4.如果then不是一个函数,将x作为promisefulfilled的value。
2.3.4. 如果x不是一个对象或函数,将x作为promise的fulfilled的value。

如果使用参与循环可变链的thenable来解决promise,使得[[Resolve]](promise, thenable)最终导致[[Resolve]](promise,thenable)再次调用的递归性质,遵循上述算法将导致无限递归。鼓励但不要求实现以检测这种递归并拒绝promise提供信息TypeError作为原因。 3.6

3.笔记

  • 3.1. 这里的“平台代码”意味着引擎,环境和promise实现代码。在实践中,此要求确保在调用事件循环并且使用新堆栈之后异步执行onFulfilledonRejected执行then。这可以用“宏任务”机制实现,例如setTimeout或者setImmediate,或者用“微任务”机制,例如MutationObserverprocess.nextTick。由于promise实现被认为是平台代码,因此它本身可能包含一个任务调度队列或“trampoline”,其中调用处理程序。

  • 3.2.也就是说,严格模式thisundefined在其中;在草率模式下,它将成为全局对象。

  • 3.3. promise2 === promise1只要实现满足所有要求,实现可以允许。每个实施应记录它是否可以生产promise2 === promise1以及在什么条件下生产。

  • 3.4. 一般来说,x如果它来自当前的实现,那么它只是一个真正的promise。该子句允许使用特定于实现的方法来采用已知符合的promise的状态。

  • 3.5. 此过程首先存储引用x.then,然后测试该引用,然后调用该引用,避免多次访问该x.then属性。这些预防措施对于确保访问者属性的一致性非常重要,访问者属性的值可能会在检索之间发生变化。

  • 3.6. 实现应不设置thenable链的深度任何限制,并假设超出任何限制递归将是无限的。只有真正的周期才能导致TypeError;如果遇到无限的不同的可能的链,那么永远递归就是正确的行为。