Skip to content

Promise 理解

Promise 执行顺序总结分析

代码分析

javascript
const p1 = Promise.resolve(1);
const p2 = new Promise(resolve => resolve(p1));
p2.then(res => console.log(2));
p1.then(() => console.log(1)).then(() => console.log(4));
console.log(3);

执行顺序

输出结果:3, 1, 4, 2

详细执行过程

1. Promise 创建阶段

  • 创建 p1Promise.resolve(1) 创建一个已解决(fulfilled)的 Promise,值为 1
  • 创建 p2:调用 Promise.resolve(),传入一个 executor 函数 resolve => resolve(p1)

2. p2 构造过程详解

当执行 p2 的构造函数时:

  1. 立即执行传入的 executor:resolve => resolve(p1)
  2. 调用内部的 resolve 函数,参数为 p1
  3. 进入 resolvePromise 函数处理:
    javascript
    if (value instanceof Promise) {
      // value 是 p1
      value.then(resolve, reject); // 关键:建立依赖关系
      return;
    }
  4. 由于 p1 已经是 fulfilled 状态,p1.then(resolve, reject) 会将 p2 的 resolve/reject 函数加入微任务队列

3. 回调注册顺序

按时间顺序注册的回调:

  1. p1.then(p2_resolve, p2_reject) - 来自 resolvePromise 内部调用
  2. p1.then(() => console.log(1)) - 显式注册到 p1
  3. .then(() => console.log(4)) - 链式 Promise 的回调
  4. p2.then(res => console.log(2)) - 注册到 p2

4. 微任务队列执行

微任务执行顺序:

  1. p2_resolve - 使 p2 变为 fulfilled 状态,触发 p2.then 回调注册
  2. () => console.log(1) - p1 的第一个回调
  3. () => console.log(4) - 链式 Promise 回调
  4. () => console.log(2) - p2 的回调(在步骤 1 中触发注册)

5. 最终输出

3  // 同步代码立即执行
1  // p1 的第一个回调
4  // 链式 Promise 回调
2  // p2 的回调

核心要点

  1. Promise 解析机制:当一个 Promise 被 resolve 为另一个 Promise 时,会通过 then 方法建立依赖关系
  2. 微任务队列:Promise 回调都放入微任务队列,按注册顺序执行
  3. 状态传播p2 的状态依赖于 p1,只有 p1 完成后 p2 才能变为 fulfilled
  4. 执行时机:虽然 p2 的 resolve 函数注册最早,但 p2.then 的回调是在 p2 状态改变后才注册的,所以执行较晚

这个例子完美展示了 Promise 的异步特性、状态传播机制以及微任务队列的执行顺序。

拓展

js
const p1 = Promise.resolve(1);
const p2 = new Promise(resolve => resolve(p1));
p2.then(res => console.log(2));
p1.then(() => console.log(1)).then(() => console.log(4));
console.log(3);

// 对比下面的代码 输出结果有何不同,理解什么是promise吸收

const p3 = Promise.resolve(1);
const p4 = Promise.resolve(resolve => resolve(p3));
p4.then(res => console.log(2));
p3.then(() => console.log(1)).then(() => console.log(4));
console.log(3);

Released under the MIT License.