实现Promises/A+,规范翻译

477 阅读5分钟

第一次翻译,肯定存在不明确或者错误的地方,仅作自己记录使用

该文章翻译自Promises/A+

Promise为开发人员提供一个开放、标准、可靠的JavaScript承诺

一个promise代表了一个异步操作的最终结果。Promise提供了最基本的then方法来注册回调(callbacks)以接受一个promise成功的返回值或者其失败原因。

为了给所有符合Promises/A+规范的Promise实现提供一个规范的可交互的基本方式——then,本为详细说明了then方法的行为特性。我们应该确保该规范是十分明确以及稳定的。只有在Promises/A+组织经过仔细考虑、讨论和测试后才会新增一些大范围的、不向后兼容的更改,而在通常情况下该组织只是偶尔做一些微小的向后兼容的更改以解决新发现的极端问题。

从历史上看,Promises/A+进一步详细丰富了早期Promises/A提案的行为规范,使规范能够涵盖日常需求的行为并省略了Promises/A中未指明或有问题的部分。

在目前阶段,Promises/A+规范的核心并不是阐明如何创建Promise或者更改其状态为fulfillreject,而是选择专注于提供可互操作的then方法。而在未来的工作中,一些配套的工具可能会满足以上需求。

1. 术语

1.1 promise: 符合本规范并具有then方法的一个对象或者函数

1.2 thenable: 定义了then方法的一个对象或者函数

1.3 value: 任何符合JavaScript规范的值(可以是 undefined、一个thenable或者一个promise

1.4 exception: 被throw语句抛出的一个value

1.5 reason: 指明一个promise为何被转换为reject状态的一个value

2. 要求

2.1 Promise状态

一个promise的状态必须是以下三个状态中的一个:pendingfulfilledrejected

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

以上描述中的 禁止转变 表示一个不可改变的判断(比如 ===),但是不以为之它是深层次不可变。

译者注:不太理解,可能是类似对象?

let a = { name: 'Nicholas' }
// 可以更改 a.name?

2.2 then方法

一个promise必须提供一个可以接触到其目前或者最终状态下的value或者reasonthen方法。

promisethen方法接受两个参数,表现形式如下:

promise.then(onFulfilled, onRejected)

2.2.1 onFulfilledonRejected方法都不是必需的:

  • 如果onFulfilled不是一个方法,则必须被忽略
  • 如果onRejected不是一个方法,则必须被忽略

2.2.2 如果onFulfilled是一个方法:

  • 该方法只能在promise的状态为fulfilled后被调用,并且该promisevalue是该方法的第一个参数。
  • 该方法在promise状态变为fulfilled之前禁止被调用。
  • 该方法只能被调用一次。

2.2.3 如果onRejected是一个方法:

  • 该方法只能在promise的状态为rejected后被调用,并且该promisereason是该方法的第一个参数。
  • 该方法在promise状态变为rejected之前禁止被调用。
  • 该方法只能被调用一次。

2.2.4 在执行上下文堆栈仅包含平台代码之前,不得调用onFulfilledonRejected

译者注:主要是为了保证异步调用两个方法,可以通过塞入宏任务队列或者微任务队列中。

2.2.5 onFulfilledonRejected必须以方法的形式调用(即不得使用this)。

2.2.6 then方法在同一个promise上可以调用多次:

  • promise状态变为fulfilled时(或者已为fulfilled时),所有的onFulfilled回调都应该按照各自then调用的顺序来执行
  • promise状态变为rejected时(或者已为rejected时),所有的onRejected回调都应该按照各自then调用的顺序来执行

2.2.7 then方法必须返回一个promise:

promise2 = promise1.then(onFulfilled, onRejected)

  • 2.2.7.1 只要onFulfilled或者onRejected返回一个valuex,该表达式需要运行 Promise Resolution Procedure,表达式为[[Resolve]](promise2, x)
  • 2.2.7.2 只要onFulfilled或者onRejected throw一个epromise2必须以e作为理由状态为rejected
  • 2.2.7.3 如果onFulfilled不是一个方法并且promise1的状态是fulfilled时,promise2的状态必须是fulfilled并且其value应和promise1value一样
  • 2.2.7.3 如果onRejected不是一个方法并且promise1的状态是rejected时,promise2的状态必须是rejected并且其reason应和promise1reason一样

2.3 Promise Resolution Procedure

Promise Resolution Procedure是一种抽象的操作,它将promisevalue作为输入,表现形式为[[Resolve]](promise, x)。如果x是一个thenable,它(Promise Resolution Procedure)会试图将promise采用x的状态,因为至少x看起来像是一个promise。否则将promise变为fulfilled,并将其value设定为x

该操作(Promise Resolution Procedure)使得满足Promises/A+规范的promise可互操作。同时它也使得那些不太规范但是又有then方法的一些实现可以互操作。

我们通过以下步骤来运行Promise Resolution Procedure

2.3.1 如果promisex是同一个对象,则以TypeErrorreject掉promise

2.3.2 如果x是一个promise,则采用其状态:

  • 如果x处于pending状态,promise必须在x变为fulfilled或者rejected前保持pending状态
  • 如果/当x状态(变)为fulfilled,以xvalueresolvepromise
  • 如果/当x状态(变)为rejected,以xreasonrejectpromise

2.3.3 其他情况下,如果x是一个对象或者方法:

  • then指向x.then
  • 如果在检索属性x.then时抛出了异常e,则以ereasonrejectpromise
  • 如果then是一个方法,以x为上下文执行它,参数即为then的参数resolvePromiserejectPromise
    • 如果/当 resolvePromise被调用且参数为y,则继续调用[[Resolve]](promise, y)
    • 如果/当rejectPromise被调用且理由为r,则用r拒绝掉promise
    • 如果rejectPromiseresolvePromise都被调用过,则只采用第一次调用来应用前两个准则
    • 如果在调用then方法时遇到了错误e:
      • 如果resolvePromise或这rejectPromise被调用过,则运用之前的规则并忽略e
      • 其他情况下用e reject promise

2.3.4 如果x不是一个对象或者方法,则用x fulfilled promise

GitHub地址