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)。 - 参数可选:
onFulfilled和onRejected都是可选参数。- 如果它们不是函数类型,则必须被忽略。
onFulfilled特性: 必须在 Promise 状态变为 执行(Fulfilled) 时调用,并将value作为第一个参数。它不能在 Promise 执行完成前被调用,且调用次数不能超过一次。onRejected特性: 必须在 Promise 状态变为 拒绝(Rejected) 时调用,并将reason作为第一个参数。它不能在 Promise 被拒绝前被调用,且调用次数不能超过一次。- 调用时机:
onFulfilled和onRejected只能在执行上下文堆栈仅包含平台代码时被调用。这通常意味着他们的执行必须被放入事件循环的队列(如微任务) 中,从而实现异步执行。 - 多次调用: 同一个 Promise 的
then方法可以被多次调用。当 Promise 状态变更后,所有对应的回调函数必须按照它们被添加的顺序执行。 - 返回值 (链式调用):
then方法必须返回一个 Promise 对象(记作promise2)。promise2的状态由onFulfilled或onRejected的执行结果(记作x)决定,具体处理规则由 Promise 解析过程定义。
3. Promise 解析过程
Promise 解析过程是一个抽象操作,它接收一个 Promise(promise2)和一个值(x)作为输入。这是实现链式异步操作最核心的部分,需要特别关注:
- 如果
promise2和x是同一个对象,则会导致循环引用,必须拒绝promise2。 - 如果
x是一个 Promise,则promise2的状态和最终值将完全由x决定。 - 如果
x是一个对象或函数(可能是一个 Thenable),则会尝试取它的then方法。然后,像调用 Promise 的then方法一样调用该then方法,将promise2的resolve和reject函数作为参数传入,以保证正确消耗这个 Thenable 对象。 - 如果
x是一个普通值,则直接以x为值调用resolve方法。
这个递归过程确保了任何符合 then 方法的对象都能被顺利解析,为各种异步操作提供了统一的互操作性基础。你代码中的 resolvePromise 函数正是严格遵循了这一规范。
⚖️ 与 ECMAScript Promise 的关系
值得注意的是,Promise/A+ 规范侧重于定义 then 方法的行为,以提供一个可互操作的基础。它并没有规定 Promise 构造函数(new Promise)或 catch、finally、all、race 等方法的行为。ECMAScript 2015 (ES6) 引入的 Promise 标准在 then 方法的行为上遵循了 Promise/A+ 规范,并在此之上扩展了这些额外的方法。因此,你之前看到的 MyPromise 实现中那些 all、race 等静态方法,是 ES6 Promise 标准在 Promise/A+ 规范基础上的增强。
💎 总结
Promise/A+ 规范的成功在于它准确定义了一个简洁、稳固的行为核心(状态机和 then 方法),并定义了详尽的互操作规则,让开发者能轻松地进行链式异步编程。
你之前实现 MyPromise 时,已经严格遵循了这套规范,所以整体框架会显得如此清晰~