Promise 解决过程(Promise Resolution Procedure)详解

6 阅读3分钟

Promise 解决过程是 Promise A+ 规范的核心机制,用于处理 then 回调返回值与 Promise 状态的关系。以下从规范角度结合代码示例解析这一过程。

一、解决过程的核心定义

Promise 解决过程是一个抽象操作 [[Resolve]](promise, x),表示将 promise 的状态与值根据 x 的类型和状态进行解析。其核心逻辑是:x 是 Promise 或 Thenable(具有 then 方法),则使 promise 接受 x 的状态;否则用 x 的值完成 promise

二、解决过程的具体规则

1. xpromise 为同一对象

  • 规则:若 promisex 指向同一实例,以 TypeError 拒绝 promise,避免循环引用。
  • 示例
    const promise = new Promise(resolve => {
      resolve(promise); // promise 和 x 为同一对象
    });
    
    promise.then(
      value => console.log('成功'),
      reason => console.log('错误:', reason) // 输出:错误: TypeError
    );
    

2. x 是 Promise 实例

  • 规则
    • x 处于 pendingpromise 保持 pending,直至 x 状态确定。
    • x 处于 fulfilledpromise 以相同值 fulfilled
    • x 处于 rejectedpromise 以相同原因 rejected
  • 示例
    function createPromise(delay, value) {
      return new Promise(resolve => {
        setTimeout(() => resolve(value), delay);
      });
    }
    
    const p1 = createPromise(100, 'p1 resolved');
    const p2 = new Promise(resolve => {
      resolve(p1); // x 是 Promise
    });
    
    p2.then(
      value => console.log('p2 结果:', value), // 输出:p2 结果: p1 resolved
      reason => console.log('p2 错误:', reason)
    );
    

3. x 是 Object 或 Function(Thenable)

  • 规则
    1. 尝试获取 x.then,若获取时抛出异常 e,则以 e 拒绝 promise
    2. then 是函数,调用 x.then(resolvePromise, rejectPromise),其中:
      • resolvePromise(y):递归执行 [[Resolve]](promise, y)
      • rejectPromise(r):以 r 拒绝 promise
      • resolvePromiserejectPromise 被多次调用,仅首次有效。
    3. 若调用 then 时抛出异常 e,且 resolvePromise/rejectPromise 未被调用,则以 e 拒绝 promise
    4. then 不是函数,以 x 完成 promise
  • 示例
    // 定义 Thenable 对象
    const thenable = {
      then(resolve, reject) {
        console.log('调用 then 方法');
        setTimeout(() => {
          resolve('thenable value'); // 调用 resolvePromise
        }, 500);
      }
    };
    
    const promise = new Promise(resolve => {
      resolve(thenable); // x 是 Thenable
    });
    
    promise.then(
      value => console.log('结果:', value), // 输出:结果: thenable value
      reason => console.log('错误:', reason)
    );
    

4. x 是普通值(非对象、非函数)

  • 规则:以 x 直接完成 promise
  • 示例
    const promise = new Promise(resolve => {
      resolve(42); // x 是普通值
    });
    
    promise.then(
      value => console.log('普通值结果:', value), // 输出:普通值结果: 42
      reason => console.log('错误:', reason)
    );
    

三、解决过程在链式调用中的体现

function promise1() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('promise1 完成');
      resolve('p1 value');
    }, 1000);
  });
}

function promise2() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('promise2 完成');
      resolve('p2 value');
    }, 2000);
  });
}

// 链式调用中返回 Promise
promise1()
  .then(value => {
    console.log('then1 接收值:', value); // then1 接收值: p1 value
    return promise2(); // x 是 Promise,触发解决过程
  })
  .then(value => {
    console.log('then2 接收值:', value); // then2 接收值: p2 value(等待 promise2 完成)
  })
  .catch(error => {
    console.log('错误:', error);
  });

解决过程解析

  1. promise1 完成后,then1 返回 promise2x 是 Promise)。
  2. [[Resolve]](promise2, x) 执行:
    • promise2 处于 pending,当前 then2 的 Promise 保持 pending
    • promise2 完成时,当前 Promise 以相同值完成,触发 then2 回调。

四、解决过程中的异常处理

const promise = new Promise(resolve => {
  // 模拟 Thenable 中抛出异常
  resolve({
    then: function() {
      throw new Error('Thenable 内部错误');
    }
  });
});

promise.then(
  value => console.log('成功:', value),
  reason => console.log('错误:', reason) // 输出:错误: Thenable 内部错误
);

异常流程

  1. resolve 传入 Thenable 对象。
  2. 获取 x.then 时未出错,但调用 x.then 时抛出异常。
  3. 解决过程捕获异常,以该异常拒绝 promise

五、解决过程的核心意义

  1. 保证状态一致性:无论 x 是普通值、Promise 还是 Thenable,解决过程确保 promise 状态与 x 正确关联。
  2. 支持链式调用:通过递归处理 x,实现 Promise 链的无缝衔接。
  3. 兼容不同实现:使原生 Promise 与第三方 Promise 库(如 Bluebird)可相互操作。

理解 Promise 解决过程是掌握 Promise 异步编程的关键,尤其在处理复杂链式调用和异常场景时,能帮助开发者预测和调试代码行为。