假设我们有一个包含Next.js代码的文件:
process.nextTick(()=>{
console.log('nextTick')
})
queueMicrotask(()=>{
console.log('queueMicrotask')
})
console.log('console.log')
我们在package.json中将module system设置为"type": "commonjs"
我们期望控制台中的输出是什么?Node.js官方文档说道:
- 在Node.js事件循环的每一轮中,process.nextTick()队列总是在微任务队列之前处理 *
因此,在控制台中,我们期望
console.log
nextTick
queueMicrotask
这很有效。直到我将模块系统更改为"type": "module"
。在此更改之后,我经常在process.nextTick之前执行queueMicrotask。控制台输出为:
console.log
queueMicrotask
nextTick
有人能解释这种行为吗?我假设这种行为在某种程度上与模块评估和执行过程有关,并且nextTick queueMicrotask在某种程度上进入了不同的事件循环,因为模块意味着异步执行(在浏览器中)。尽管如此,这种猜测是非常不可靠的,从我的Angular 来看,是不合逻辑的。尽管如此,我还是没有一个合理的解释。
1条答案
按热度按时间rkkpypqq1#
这是因为,当作为ESM运行时,脚本实际上已经处于微任务阶段。因此,从那里排队的新微任务将在“
nextTick
”回调之前执行。两个队列在这里的行为是相同的,因为它们在完成之前都是“实时”清空的,因此任何新的队列回调都将在访问任何其他队列之前执行。
无论主脚本如何计算,上面的脚本将始终输出“In microtask the赢家is microtask”和“In nextTick the winner is nextTick”。(但两个语句的顺序会发生变化)。
在node中,ESM模块脚本实际上是从 async/await 函数中执行的:
所以这意味着当我们的脚本运行时,我们已经在微任务阶段,因此从那里排队的新微任务将首先执行。
当作为CommonJS运行时,我们仍然处于轮询阶段。入口点在这里,然后所有的事情直到实际的评估是同步的。从轮询阶段开始,
nextTick
将战胜微任务阶段:这将始终输出“in poll phase the赢家is nextTick”,无论主脚本如何被评估。