Node.js事件循环:CJS与ESM中nextTick与Promise回调执行顺序为何反转?
CommonJS与ES模块中process.nextTick和Promise队列执行顺序差异解析
现象复现
CommonJS模块(index.js)
Promise.resolve().then(() => console.log("this is Promise.resolve 1")); process.nextTick(() => console.log("this is process.nextTick 1"));
执行日志:
this is process.nextTick 1 this is Promise.resolve 1
ES模块(index.mjs)
Promise.resolve().then(() => console.log("this is Promise.resolve 1")); process.nextTick(() => console.log("this is process.nextTick 1"));
执行日志:
this is Promise.resolve 1 this is process.nextTick 1
核心原因:模块加载阶段的队列初始化差异
Node.js处理不同模块类型时,模块初始化时机与微任务队列触发逻辑存在本质差异:
CommonJS模块执行逻辑
CJS模块同步加载执行,模块代码运行时,process.nextTick和Promise.resolve().then的回调会分别加入nextTickQueue和PromiseJobs两个微任务队列。Node.js默认微任务优先级为nextTickQueue>PromiseJobs,模块代码执行完毕后会先清空nextTickQueue,再处理PromiseJobs,因此process.nextTick回调先执行。ES模块执行逻辑
ESM采用异步加载机制,Node.js会将模块的执行逻辑封装到一个Promise回调中触发。这意味着你在ESM模块中添加的Promise.resolve().then回调,和模块执行的外层Promise属于同一PromiseJobs队列批次;而process.nextTick的回调是在外层Promise之后才被加入nextTickQueue。当外层Promise执行时,会先处理同批次的PromiseJobs回调(即代码中的Promise回调),之后才会轮到nextTickQueue中的回调,最终呈现相反的执行顺序。
内容的提问来源于stack exchange,提问作者Vishwas
相关产品推荐
相关产品推荐

