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

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

一、解决过程的核心定义

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

二、解决过程的具体规则

1. x 与 promise 为同一对象

  • 规则 :若 promise 和 x 指向同一实例,以 TypeError 拒绝 promise,避免循环引用。

  • 示例 :

    javascript 复制代码
    const promise = new Promise(resolve => {
      resolve(promise); // promise 和 x 为同一对象
    });
    
    promise.then(
      value => console.log('成功'),
      reason => console.log('错误:', reason) // 输出:错误: TypeError
    );

2. x 是 Promise 实例

  • 规则 :

    • 若 x 处于 pending,promise 保持 pending,直至 x 状态确定。
    • 若 x 处于 fulfilled,promise 以相同值 fulfilled。
    • 若 x 处于 rejected,promise 以相同原因 rejected。
  • 示例 :

    javascript 复制代码
    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。
      • 若 resolvePromise 和 rejectPromise 被多次调用,仅首次有效。
    3. 若调用 then 时抛出异常 e,且 resolvePromise/rejectPromise 未被调用,则以 e 拒绝 promise。
    4. 若 then 不是函数,以 x 完成 promise。
  • 示例 :

    javascript 复制代码
    // 定义 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。

  • 示例 :

    javascript 复制代码
    const promise = new Promise(resolve => {
      resolve(42); // x 是普通值
    });
    
    promise.then(
      value => console.log('普通值结果:', value), // 输出:普通值结果: 42
      reason => console.log('错误:', reason)
    );

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

javascript 复制代码
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 返回 promise2(x 是 Promise)。
  2. [[Resolve]](promise2, x) 执行:
    • promise2 处于 pending,当前 then2 的 Promise 保持 pending。
    • 当 promise2 完成时,当前 Promise 以相同值完成,触发 then2 回调。

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

javascript 复制代码
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 异步编程的关键,尤其在处理复杂链式调用和异常场景时,能帮助开发者预测和调试代码行为。

相关推荐
仿生狮子2 小时前
OpenAI 攻下千禧年难题之后,开发者似乎无动于衷
前端·数学·vibecoding
夏幻灵6 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
Lvan的前端笔记6 小时前
docker:每个前端项目一个 Nginx 容器还是只有一个Nginx容器
前端·nginx·docker
三天不学习6 小时前
Egg.js 4 突然爆火,原因是否归结于AI 原生落地需求爆发?
前端·javascript·全栈·egg.js
xcs194057 小时前
前端 vue 的前端页面debugger 进不去
前端·javascript·vue.js
明月_清风8 小时前
Deno 终局来了:从挑战 Node 到被 Cloudflare 收编
前端·后端·node.js
Csvn9 小时前
框架性能优化
前端
回眸&啤酒鸭10 小时前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
用户693717500138411 小时前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员11 小时前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端