English 中文(简体)
process.nextTick vs queueMicrotask in commonJs and ESM. What is the execution order?
原标题:

Let s imagine we have a file containing next JS code:

process.nextTick(()=>{
    console.log( nextTick )
})

queueMicrotask(()=>{
    console.log( queueMicrotask )
})

console.log( console.log )

and we ve set module system to "type": "commonjs" in our package.json

What output in console do we expect? Node.js official documentation says:

The process.nextTick() queue is always processed before the microtask queue within each turn of the Node.js event loop

So, in console we expect

console.log
nextTick
queueMicrotask

And that works. Until I change module system to "type": "module". After that change I constantly have queueMicrotask executed before process.nextTick . Console output is:

console.log
queueMicrotask
nextTick

Can anybody explain this behaviour? I assume that this behaviour is somehow related to module evaluation and execution process and that nextTick queueMicrotask somehow get into different event loop ticks as module implies async execution(in browser). Still, that guess is very shaky and from my point of view, is illogical. Nevertheless, I still don t have a plausible explanation.

问题回答

This is because, when ran as ESM, the script is actually already in the microtask phase. So a new microtask queued from there will get executed before a "nextTick" callback.


Both queues behave the same here in that they re being emptied "live" until completion, and thus any new queued callback will get executed before any other queue is visited.

queueMicrotask(() => {
  let winner;
  console.log("in microtask, the winner is");
  queueMicrotask(() => {
    if (!winner) console.log(winner = "microtask");
  });
  process.nextTick(() => {
    if (!winner) console.log(winner = "nextTick");
  });
});
process.nextTick(() => {
  let winner;
  console.log("in nextTick, the winner is");
  queueMicrotask(() => {
    if (!winner) console.log(winner = "microtask");
  });
  process.nextTick(() => {
    if (!winner) console.log(winner = "nextTick");
  });
});

The above script will always output "In microtask the winner is microtask" and "In nextTick the winner is nextTick", no matter how the main script is evaluated. (The order of both statements will change though).


In node, ESM module scripts are actually evaluated from an async/await function:

 async run() {
  await this.instantiate();
  const timeout = -1;
  const breakOnSigint = false;
  try {
    await this.module.evaluate(timeout, breakOnSigint);

So this means that when our script is ran, we re already inside the microtask phase, and thus new microtasks that get queued from there will get executed first.

When ran as CommonJS though, we re still in the poll phase. The entry point is here, then everything until the actual evaluation is synchronous. And from the poll phase, nextTick will win against the microtask phase:

setImmediate(() => {
  let winner;
  console.log("in poll phase, the winner is");
  queueMicrotask(() => {
    if (!winner) console.log(winner = "microtask");
  });
  process.nextTick(() => {
    if (!winner) console.log(winner = "nextTick");
  });
});

This will always output "in poll phase the winner is nextTick", no matter how the main script is being evaluated.





相关问题
selected text in iframe

How to get a selected text inside a iframe. I my page i m having a iframe which is editable true. So how can i get the selected text in that iframe.

How to fire event handlers on the link using javascript

I would like to click a link in my page using javascript. I would like to Fire event handlers on the link without navigating. How can this be done? This has to work both in firefox and Internet ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Clipboard access using Javascript - sans Flash?

Is there a reliable way to access the client machine s clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use ...

javascript debugging question

I have a large javascript which I didn t write but I need to use it and I m slowely going trough it trying to figure out what does it do and how, I m using alert to print out what it does but now I ...

Parsing date like twitter

I ve made a little forum and I want parse the date on newest posts like twitter, you know "posted 40 minutes ago ","posted 1 hour ago"... What s the best way ? Thanx.

热门标签