在上一篇博客里,讲解了 Promise 的核心逻辑——从“pending/fulfilled/rejected”的状态流转,到 then/catch/finally 的链式调用,再到 Promise.all 等静态方法的场景化使用等等。这一篇是对 Promise 检验和巩固。

上一篇文章👉Promise学习链接

题目 1

const promise = new Promise((resolve, reject) => {
	console.log(1);
	resolve(1);
	console.log(2);
})

promise.then((res) => {
	console.log(3);
})

console.log(4);

代码执行分析

  1. Promise构造函数中的代码立即执行
const promise = new Promise((resolve, reject) => {
  console.log(1);    // 立即执行,输出 1
  resolve(1);        // 将promise状态改为resolved
  console.log(2);    // 立即执行,输出 2
})
  1. then回调被添加到微任务队列
promise.then((res) => {
  console.log(3);    // 这个回调被添加到微任务队列
})
  1. 同步代码继续执行
    执行 console.log(5),输出 5(同步代码优先于所有异步任务)。

  2. 事件循环处理微任务队列
    执行微任务队列中的 console.log(3)

题目关键点

Promise构造函数中的executor函数是同步执行的,不是微任务
● 只有通过 then、catch、finally 注册的回调才是微任务
● 微任务会在同步代码执行完毕后才执行
● 所以执行顺序是:同步代码(1,2,4) → 微任务(3)

题目 2

const promise = new Promise((resolve, reject) => {
  console.log(1);
  setTimeout(() => {
    console.log(2);
    resolve();
    console.log(3);
  }, 1000);
});
promise.then(() => {
  console.log(4);
});
console.log(5);

代码执行分析

  1. Promise 创建阶段
    new Promise(...) 时,构造函数内的代码会立即同步执行

    • 执行 console.log(1),输出 1
    • setTimeout 被添加到宏任务队列,延迟 1 秒后执行;
    • 此时 Promise 处于 pending 状态。
  2. then 回调注册(等待状态)
    调用 promise.then(...) 时,由于 Promise 仍为 pendingthen 回调不会立即执行,而是被暂存,等待 Promise 状态变为 fulfilled 后触发。

  3. 同步代码执行
    执行 console.log(5),输出 5(同步代码优先于所有异步任务)。

  4. 宏任务执行(1 秒后)
    延迟结束后,setTimeout 回调从宏任务队列取出执行:

    • 执行 console.log(2),输出 2
    • 调用 resolve(),将 Promise 状态改为 fulfilled
    • 执行 console.log(3),输出 3resolve 后仍会执行后续同步代码)。
  5. 微任务执行(当前事件循环末尾)
    Promise 状态变更后,暂存的 then 回调被加入微任务队列,在宏任务执行完毕后立即执行:

    • 执行 console.log(4),输出 4

最终输出顺序

1
5
2
3
4

关键概念

  • 宏任务(如 setTimeout)需等待当前事件循环的同步代码、微任务执行完毕后才执行;
  • 微任务(如 Promise.then)优先级高于宏任务,在同步代码结束后、宏任务开始前执行。

题目3

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve();
  }, 1000);
});

const promise2 = promise1.catch(() => {
  return 2;
});

console.log('promise1', promise1);
console.log('promise2', promise2);

setTimeout(() => {
  console.log('promise1', promise1);
  console.log('promise2', promise2);
}, 2000);

代码执行分析

  1. promise1 创建(初始状态)
    new Promise(...) 时,setTimeout 被加入宏任务队列,1 秒后执行 resolve()
    此时 promise1 处于 pending 状态。

  2. promise2 创建(依赖 promise1 状态)
    promise1.catch(...) 会创建一个新的 Promise(promise2):

    • catch 仅在 promise1 状态变为 rejected 时触发;
    • 由于 promise1 最终会 resolvecatch 回调不会执行;
    • 此时 promise2 同样处于 pending 状态,等待 promise1 的状态结果。
  3. 同步输出(初始状态打印)
    执行 console.log('promise1', promise1)console.log('promise2', promise2),两者均输出 Promise {<pending>}

  4. 宏任务 1 执行(1 秒后)
    setTimeout 回调执行 resolve(),promise1 状态变为 fulfilled
    由于 promise1 未被拒绝,promise2 会“继承”promise1 的状态,也变为 fulfilled(值为 undefined,因 catch 未触发)。

  5. 宏任务 2 执行(2 秒后)
    再次打印两个 Promise 的状态,均输出 Promise {<fulfilled>: undefined}

最终输出顺序

promise1 Promise {<pending>}
promise2 Promise {<pending>}
promise1 Promise {<fulfilled>: undefined}
promise2 Promise {<fulfilled>: undefined}

关键概念

  • catchthen(null, onRejected) 的语法糖,仅在原 Promise 被拒绝时触发;
  • then/catch 创建的新 Promise,其状态依赖原 Promise 的状态:原 Promise 成功则新 Promise 也成功,原 Promise 失败则执行回调后新 Promise 可能成功(若回调返回正常值);
  • Promise 状态一旦确定(fulfilled/rejected),就会永久不变。

题目 4

async function m1() {
  return 1;
}

async function m2() {
  const n = await m1();
  console.log(n);
  return 2;
}

async function m3() {
  const n = m2();
  console.log(n);
  return 3;
}

m3().then((n) => {
  console.log(n);
});

m3();

console.log(4);

代码执行分析

  1. 函数定义阶段
    定义 m1/m2/m3 三个 async 函数,此时仅声明,未执行。

  2. 第一个 m3() 执行(同步优先)

    • 进入 m3,调用 m2()
    • m2()async函数,立即返回一个pending状态的Promise(未执行内部逻辑),将 m2 内部代码(含 await m1())暂存;
    • 执行 console.log(n),输出 [object Promise]
    • m3 执行到 return 3,返回一个 pending Promise(因 m2 未完成),并为其注册 then 回调。
  3. 第二个 m3() 执行(重复同步逻辑)

    • 再次调用 m3(),重复上述步骤:调用 m2() 得到 pending Promise,执行 console.log(n) 输出 [object Promise],返回 pending Promise(无 then 回调)。
  4. 同步代码
    执行 console.log(4),输出 4

  5. 微任务执行(异步队列处理)
    同步代码结束后,处理暂存的 async 函数内部逻辑:

    • 第一个 m2() 执行:调用 m1()async 函数返回 Promise.resolve(1)),await 等待后执行 console.log(n) 输出 1m2 返回 Promise.resolve(2)
    • 第一个 m3 的 Promise 变为 fulfilled(值为 3),触发 then 回调,输出 3
    • 第二个 m2() 执行:同理,调用 m1() 后执行 console.log(n) 输出 1m2 返回 Promise.resolve(2)
    • 第二个 m3 的 Promise 变为 fulfilled(值为 3),无 then 回调,不输出。

最终输出顺序

[object Promise]  // 第一个m3()中打印m2()返回的Promise
[object Promise]  // 第二个m3()中打印m2()返回的Promise
4                // 同步代码console.log(4)
1                // 第一个m2()中打印await m1()的结果
3                // 第一个m3()的then回调打印结果
1                // 第二个m2()中打印await m1()的结果

关键概念

  • 调用 async 函数时,先同步执行其内部代码,直到遇到第一个 await
  • 遇到 await 时,会暂停当前 async 函数执行,返回一个 pending 状态的 Promise, await 右侧的表达式会被执行
  • await 后续的代码会被放入微任务队列,等待 await 右侧的 Promise 完成后再执行
  • async 函数的返回值会自动包装为 Promise.resolve(返回值),即使返回普通值。

题目 5

var a;
var b = new Promise((resolve, reject) => {
  console.log("promise1");
  setTimeout(() => {
    resolve();
  }, 1000);
})
.then(() => {
  console.log("promise2");
})
.then(() => {
  console.log("promise3");
})
.then(() => {
  console.log("promise4");
});

a = new Promise(async (resolve, reject) => {
  console.log(a);
  await b;
  console.log(a);
  console.log("after1");
  await a;
  resolve(true);
  console.log("after2");
});

console.log("end");

代码执行分析

  1. 变量声明与 b 初始化

    • 声明 a(初始值 undefined);
    • 创建 b:Promise 构造函数同步执行 console.log("promise1"),输出 promise1setTimeout 加入宏任务队列(1 秒后 resolve);
    • b 注册 3 个 then 回调,均暂存(等待 b 状态变更),此时 bpending
  2. a 初始化(同步+异步暂停)

    • 创建 a 的 Promise 时,构造函数内代码同步执行:
      • 打印 a(此时 a 未完成赋值,输出 undefined);
      • 遇到 await b:暂停构造函数执行,等待 b 完成;将后续代码(console.log(a) 及之后)暂存;
    • 完成 a 赋值,此时 apending 状态。
  3. 同步代码收尾
    执行 console.log("end"),输出 end

  4. 宏任务执行(1 秒后)
    setTimeout 回调执行 resolve()b 状态变为 fulfilled,触发其 then 链:

    • 第一个 then 执行 console.log("promise2"),输出 2
    • 第二个 then 执行 console.log("promise3"),输出 3
    • 第三个 then 执行 console.log("promise4"),输出 4
    • b 整个链条执行完毕,状态最终为 fulfilled
  5. a 的后续代码执行(微任务)
    await b 等待结束,执行暂存的代码:

    • 打印 a(此时 apending Promise,输出 [object Promise]);
    • 打印 after1,输出 after1
    • 遇到 await a:等待 a 自身完成,但 a 正处于 pending(依赖 await a 的结果),形成循环等待
    • resolve(true)console.log("after2") 永远不会执行(a 永久 pending)。

最终输出顺序

promise1
undefined
end
promise2
promise3
promise4
[object Promise]
after1

关键概念

  • b 代表的是整个 Promise 链的最终结果,而非初始 Promise 的结果。
  • await b 会等待所有 .then() 回调依次执行完毕,直到整个链条的最后一个 Promise 完成。
  • 循环等待(如 await aa 依赖自身)会导致 Promise 永久 pending,后续代码无法执行;

题目 6

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}

async function async2() {
  console.log("async2");
}

console.log("script start");

setTimeout(function () {
  console.log("setTimeout");
}, 0);

async1();

new Promise(function (resolve) {
  console.log("promise1");
  resolve();
}).then(function () {
  console.log("promise2");
});

console.log("script end");

代码执行分析

  1. 同步代码
    执行 console.log("script start"),输出 script start
    setTimeout 加入宏任务队列(延迟 0 秒,仍需等待事件循环)。

  2. async1 执行(同步+暂停)

    • 调用 async1(),同步执行 console.log("async1 start"),输出 async1 start
    • 调用 async2(),同步执行 console.log("async2"),输出 async2async2await,返回 Promise.resolve(undefined)
    • 遇到 await async2():暂停 async1,将 console.log("async1 end") 加入微任务队列;async1 返回 pending Promise。
  3. Promise 与同步代码收尾

    • 执行 new Promise(...):构造函数同步执行 console.log("promise1"),输出 promise1;调用 resolve(),将 then 回调(console.log("promise2"))加入微任务队列;
    • 执行 console.log("script end"),输出 script end
  4. 微任务执行(同步代码结束后)
    微任务队列中有两个任务,按入队顺序执行:

    • 先执行 promise2then 回调,输出 promise2
    • 再执行 async1 暂存的 console.log("async1 end"),输出 async1 end
  5. 宏任务执行(微任务清空后)
    执行 setTimeout 回调,输出 setTimeout

最终输出顺序

script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout

关键概念

  • await 后的代码会被加入微任务队列,而非宏任务;
  • 微任务队列按“先入先出”执行,promise2thenasync1 end 先入队,因此优先执行;
  • 即使 setTimeout 延迟为 0,仍需等待微任务队列清空后才执行(宏任务优先级低于微任务)。

总结

  1. 同步优先:Promise 构造函数、async 函数内 await 之前的代码均为同步执行;
  2. 微/宏任务优先级:微任务(then/catch/await 后续代码)> 宏任务(setTimeout);
  3. 状态不可变:Promise 状态一旦变为 fulfilled/rejected,就不会再改变;
  4. async/await 本质awaitPromise.then 的语法糖,async 函数返回值自动包装为 Promise;
  5. Promise 链传递then/catch 会创建新 Promise,其状态依赖原 Promise 及回调执行结果。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐