Skip to main content

Promise/A+

📜 Promise/A+ 规范

Promise/A+ 规范为 JavaScript 的 Promise 提供了一个标准的、可互操作的开放标准。它主要定义了 Promise状态机行为和核心的 then 方法,使不同实现能够协同工作,并不涉及创建、执行或拒绝 Promise 的具体方法,这些任务留给了下层规范或具体实现。

📖 术语解释

  • Promise (承诺对象):一个拥有符合本规范 then 方法的对象或函数。
  • Thenable (拥有 then 方法的对象):任何定义了 then 方法的对象或函数。这个定义允许将不同来源的 Promise 或类似 Promise 的对象进行互操作。
  • Value (值):任何合法的 JavaScript 值(包括 undefined、Thenable 对象或 Promise 对象)。
  • Reason (拒因):表示 Promise 为何被拒绝(rejected)的 JavaScript 值。

🔍 规范的核心内容

1. Promise 的状态

一个 Promise 必须处于以下三种状态之一:

  • 等待(Pending):初始状态,可以转变为 执行(Fulfilled)拒绝(Rejected)
  • 执行(Fulfilled):操作成功完成。此状态不能再迁移到任何其他状态,并且必须有一个不可变的终值(value)
  • 拒绝(Rejected):操作失败。此状态不能再迁移到任何其他状态,并且必须有一个不可变的拒因(reason)

这里的“不可变”是指引用不可变(即 === 判断为 true),而非深层值的不可变。

2. then 方法

一个 Promise 必须提供一个 then 方法来访问其当前值、终值或拒因。

  • 方法签名: promise.then(onFulfilled, onRejected)
  • 参数可选: onFulfilledonRejected 都是可选参数。
    • 如果它们不是函数类型,则必须被忽略
  • onFulfilled 特性: 必须在 Promise 状态变为 执行(Fulfilled) 时调用,并将 value 作为第一个参数。它不能在 Promise 执行完成前被调用,且调用次数不能超过一次。
  • onRejected 特性: 必须在 Promise 状态变为 拒绝(Rejected) 时调用,并将 reason 作为第一个参数。它不能在 Promise 被拒绝前被调用,且调用次数不能超过一次。
  • 调用时机: onFulfilledonRejected 只能在执行上下文堆栈仅包含平台代码时被调用。这通常意味着他们的执行必须被放入事件循环的队列(如微任务) 中,从而实现异步执行。
  • 多次调用: 同一个 Promise 的 then 方法可以被多次调用。当 Promise 状态变更后,所有对应的回调函数必须按照它们被添加的顺序执行。
  • 返回值 (链式调用): then 方法必须返回一个 Promise 对象(记作 promise2)。promise2 的状态由 onFulfilledonRejected 的执行结果(记作 x)决定,具体处理规则由 Promise 解析过程定义。

3. Promise 解析过程

Promise 解析过程是一个抽象操作,它接收一个 Promise(promise2)和一个值(x)作为输入。这是实现链式异步操作最核心的部分,需要特别关注:

  • 如果 promise2x 是同一个对象,则会导致循环引用,必须拒绝 promise2
  • 如果 x 是一个 Promise,则 promise2 的状态和最终值将完全由 x 决定。
  • 如果 x 是一个对象或函数(可能是一个 Thenable),则会尝试取它的 then 方法。然后,像调用 Promise 的 then 方法一样调用该 then 方法,将 promise2resolvereject 函数作为参数传入,以保证正确消耗这个 Thenable 对象。
  • 如果 x 是一个普通值,则直接以 x 为值调用 resolve 方法。

这个递归过程确保了任何符合 then 方法的对象都能被顺利解析,为各种异步操作提供了统一的互操作性基础。你代码中的 resolvePromise 函数正是严格遵循了这一规范。

⚖️ 与 ECMAScript Promise 的关系

值得注意的是,Promise/A+ 规范侧重于定义 then 方法的行为,以提供一个可互操作的基础。它并没有规定 Promise 构造函数(new Promise)或 catchfinallyallrace 等方法的行为。ECMAScript 2015 (ES6) 引入的 Promise 标准在 then 方法的行为上遵循了 Promise/A+ 规范,并在此之上扩展了这些额外的方法。因此,你之前看到的 MyPromise 实现中那些 allrace 等静态方法,是 ES6 Promise 标准在 Promise/A+ 规范基础上的增强。

💎 总结

Promise/A+ 规范的成功在于它准确定义了一个简洁、稳固的行为核心(状态机和 then 方法),并定义了详尽的互操作规则,让开发者能轻松地进行链式异步编程。

你之前实现 MyPromise 时,已经严格遵循了这套规范,所以整体框架会显得如此清晰~