Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: fix process.nextTick() scheduling differences between module types #45093

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

dnalborczyk
Copy link
Contributor

@dnalborczyk dnalborczyk commented Oct 20, 2022

fixes #45048

@nodejs-github-bot nodejs-github-bot added doc Issues and PRs related to the documentations. process Issues and PRs related to the process subsystem. labels Oct 20, 2022
@@ -2515,7 +2515,8 @@ The [`queueMicrotask()`][] API is an alternative to `process.nextTick()` that
also defers execution of a function using the same microtask queue used to
execute the then, catch, and finally handlers of resolved promises. Within
Node.js, every time the "next tick queue" is drained, the microtask queue
is drained immediately after.
is drained immediately after. Note that `process.nextTick()` is scheduled
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

process.nextTick is not scheduled differently, the module's execution is scheduled differently (specifically, it is a microtask). I think we should be careful of our wording here so people don't get confused.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. The wording here is a bit off. I would suggest wording like, "The timing of the execution of tasks scheduled with process.nextTick() will vary depending on the module type being used."

@theanarkh
Copy link
Contributor

I think it is because the mjs module is loaded by promise, so after Node.js execute the code of mjs module, it will handle the microtask(except for tasks created by nextTick) created by mjs module. But the js module is loaded synchronously, so it is different. Is it right ?

@parmishh
Copy link

parmishh commented Mar 2, 2023

This code imports the nextTick function from the built-in Node.js process module and then creates a chain of asynchronous operations using Promise.resolve(), queueMicrotask(), and nextTick().

Here's a breakdown of what each part of the code does:

The Promise.resolve().then(() => console.log(2)) creates a resolved promise and schedules a callback to be executed when the promise is resolved. In this case, the callback logs the number 2 to the console.

The queueMicrotask(() => console.log(3)) adds a function to the microtask queue, which will be executed after the current task has finished executing. In this case, the function logs the number 3 to the console.

The nextTick(() => console.log(1)) schedules a callback to be executed on the next iteration of the event loop. In this case, the callback logs the number 1 to the console.

Since the callbacks are executed asynchronously, the order in which the numbers are logged to the console may not be what you expect. Here is the expected output:
1
2
3
The reason for this order is that the nextTick() callback is executed before the Promise.resolve() and queueMicrotask() callbacks. Then, the Promise.resolve() callback is executed before the queueMicrotask() callback because Promise.resolve() callbacks are executed before microtask queue callbacks. Finally, the queueMicrotask() callback is executed last.

BUT

The reason why the output is 2 3 1 instead of 1 2 3 is that the nextTick() function and queueMicrotask() function are similar but have slightly different behavior. In this case, the queueMicrotask() callback is executed before the nextTick() callback, which causes the output to be in the order of 2 3 1.

The nextTick() function schedules a callback to be executed on the next iteration of the event loop, but after I/O operations have been processed. The queueMicrotask() function, on the other hand, schedules a callback to be executed on the microtask queue, which is executed before the next event loop iteration.

In this specific case, it's possible that the nextTick() callback was delayed due to I/O operations, which allowed the queueMicrotask() callback to be executed first. This behavior can vary depending on the environment and platform that the code is running on, so it's not always predictable which callback will be executed first.

In general, when scheduling multiple asynchronous operations, it's important to be aware of the differences between the various scheduling functions and their behavior in different contexts.

@Trott @dnalborczyk @devsnek @theanarkh

If you Guys want I can do a PR

@dnalborczyk
Copy link
Contributor Author

dnalborczyk commented Mar 2, 2023

@parmishh the issue is that running the same code differs in behavior when run as a commonjs module vs. an es module. this PR corrects the expected output for the latter (esm). As I understand, the differences are working as intended, and are specific to how the modules (cjs vs. esm) have been implemented in node.js . Keep in mind that neither commonjs nor nextTick have a proper spec from TC39/WHATWG/W3C.

Anyhow, what's needed is a short description why the example code differs in both module systems.

creates a chain of asynchronous operations using Promise.resolve(), queueMicrotask(), and nextTick().

If I'm not mistaken, a Promise is actually going into the same microtask queue as something scheduled with queueMicrotask()

@outbits
Copy link

outbits commented Oct 29, 2023

I had to crawl the issues for some time to understand that the esm/cjs divergence was not a bug.
Any update on making this good to merge?

@luoxzhg
Copy link

luoxzhg commented May 4, 2024

what is blocking this PR?

@RedYetiDev RedYetiDev added the stalled Issues and PRs that are stalled. label Oct 14, 2024
Copy link
Contributor

This issue/PR was marked as stalled, it will be automatically closed in 30 days. If it should remain open, please leave a comment explaining why it should remain open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
doc Issues and PRs related to the documentations. process Issues and PRs related to the process subsystem. stalled Issues and PRs that are stalled.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wrong example
9 participants