深入解析 JavaScript 中 Promise 的执行顺序
本文详细解析 JavaScript 中 Promise 的执行机制,重点阐述微任务与宏任务的优先级差异。通过具体代码示例,分析同步任务、Promise 回调及 setTimeout 的执行顺序,并探讨链式调用中 return 语句对微任务队列的影响,帮助开发者准确掌握异步编程的执行流程。
概述
在分析 Promise 的执行流程时,有两个核心概念需要明确:
微任务与宏任务的优先级:
- 微任务:
Promise.then()、catch、finally属于微任务范畴。 - 宏任务:
setTimeout、setInterval属于宏任务范畴。 - 微任务的优先级高于宏任务:在单次事件循环(Event Loop)中,引擎会优先清空所有微任务队列,之后才会执行下一个宏任务。
- 微任务:
Promise 是基于微任务实现的:
- 当一个
Promise的状态转变为resolved或rejected时,其关联的.then()回调函数会被添加到微任务队列中,等待当前同步任务(含已入队的微任务)执行完毕后触发。
- 当一个
示例代码分析
代码分析
以下代码示例展示了 Promise 和 setTimeout 的执行顺序:
console.log("script start");
setTimeout(() => {
console.log("setTimeout 1");
}, 0);
Promise.resolve()
.then(() => {
console.log("promise 1");
return Promise.resolve().then(() => {
console.log("promise 2");
});
})
.then(() => {
console.log("promise 3");
});
setTimeout(() => {
console.log("setTimeout 2");
}, 0);
console.log("script end");
执行过程解析
同步任务:立即执行
console.log("script start")输出"script start".setTimeout的两个回调函数被放入宏任务队列,等待事件循环调度。Promise.resolve()被调用,then()的回调被放入微任务队列。
输出结果:
script start script end
主线程执行完同步任务后,开始执行微任务队列
- 微任务队列的顺序如下:
- 第一个
.then()输出"promise 1"并返回一个新的Promise。 - 新的
Promise.then()输出"promise 2"。 - 第二个
.then()输出"promise 3"。
- 第一个
输出结果:
promise 1 promise 2 promise 3- 微任务队列的顺序如下:
清空微任务队列后,开始执行宏任务队列
- 宏任务队列的两个
setTimeout回调依次执行,输出"setTimeout 1"和"setTimeout 2"。
输出结果:
setTimeout 1 setTimeout 2- 宏任务队列的两个
最终输出
综合以上,代码的输出顺序为:
script start
script end
promise 1
promise 2
promise 3
setTimeout 1
setTimeout 2
总结
- 同步任务优先执行,输出
script start和script end。 - 微任务队列优先于宏任务队列。
Promise.then()的回调会依次进入微任务队列。setTimeout的回调进入宏任务队列,最后执行。
(拓展)问题补充
如果第一个then不是返回return promise,而是直接执行一个Promise.resolve().then(() => { console.log("promise 2"); });结果是不是会变成 promise 1 → promise 3 → promise 2。结果是的。
为什么会这样?
当 Promise.resolve().then() 不通过 return 将内部的 Promise 链接到外部 then 时,promise 2 的执行不再是当前链的一部分,它会被单独添加到微任务队列的末尾,导致执行顺序的变化。
示例代码
以下是修改后的代码:
console.log("script start");
Promise.resolve()
.then(() => {
console.log("promise 1");
Promise.resolve().then(() => {
console.log("promise 2");
});
})
.then(() => {
console.log("promise 3");
});
console.log("script end");
执行过程解析
同步任务
- 输出
"script start"。 - 主线程继续,将第一个
Promise.then()的回调加入微任务队列。 - 输出
"script end"。
当前输出:
script start script end- 输出
微任务队列开始执行
- 执行第一个
.then(),输出"promise 1"。在此回调中,一个新的微任务(promise 2的回调)被加入微任务队列末尾。 - 执行第二个
.then()的回调,输出"promise 3"。
当前输出:
promise 1 promise 3- 执行第一个
微任务队列剩余任务
- 微任务队列中剩余的任务是
promise 2的回调,输出"promise 2"。
最终输出:
promise 2- 微任务队列中剩余的任务是
总输出结果
综合以上,完整的输出顺序是:
script start
script end
promise 1
promise 3
promise 2
关键点解析
链式调用和微任务队列当你不通过
return将一个新的Promise链接到当前then,它的回调会独立加入微任务队列的末尾,而不是成为当前链的一部分。对比:返回 Promise如果
return Promise.resolve().then(...),那么promise 2的执行会成为当前链的一部分,顺序为promise 1 → promise 2 → promise 3。
改变的核心代码
独立的微任务:
Promise.resolve().then(() => { console.log("promise 2"); });作为链的一部分:
return Promise.resolve().then(() => { console.log("promise 2"); });
两种写法的区别在于是否将新的 Promise 加入当前链。
总结
到此这篇关于JavaScript中Promise的执行顺序举例详析的文章就介绍到这了,更多相关JS Promise执行顺序内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38
