Nodejs: When does a tick get executed - node.js

Nodejs has a method process.nextTick(fn) which delays the execution of a function until the next tick. According to this article this can be used to emit events in the constructor of an object like this (copied from the artice):
function StreamLibrary(resourceName) {
var self = this;
process.nextTick(function() {
self.emit('start');
});
}
var stream = new StreamLibrary('fooResource');
stream.on('start', function() {
console.log('Reading has started');
});
Without process.nextTick this wouldn't have worked because the event would've been emitted before you had the chance to listen for events. However, how can you be certain that the event won't be emitted before you added an event listener? If it's fully asynchronous then there would be a chance that the next tick is executed before the end of the constructor, hence ignoring the event listener. So what are the rules behind this process? When does node executes a nextTick?

The next tick is executed on... the next tick. I think the confusion here is what you mean by "fully asynchronous".
With Node.js, all of your code runs on a single thread. No code scheduled for the next tick will be executed until the current tick is finished.
Therefore, when you emit events from the next tick within the constructor, the code that may attach handlers will all be finished executing before that next tick occurs.
The asynchronous and multi-threaded part of Node is with handling operations such as network and IO. Those function calls run while your JavaScript code is running, but when data is passed back to your code, it won't run until that next tick.

Related

In Node.js, setImmediate() callbacks get executed on current event loop tick, or on the next one?

In the official docs, "setImmediate() vs setTimeout()" section, it says:
"setImmediate() is designed to execute a script once the current poll phase completes", and as i understand, it means also current tick/event loop cycle.
However later in the "process.nextTick() vs setImmediate()" section, it says:
"setImmediate() fires on the following iteration or 'tick' of the event loop".
So which one is the correct answer, did i miss anything here?
Thanks in advance.
Docs relevant page: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
As you can see by the image below:
The diagram is from Event Loop and the Big Picture — NodeJS Event Loop Part 1 By Deepal Jayasekara
"The boxes around the circle illustrate the queues of the different phases we seen before, and the two boxes in the middle illustrate two special queues that need to be exhausted before moving from one phase to the other. The “next tick queue” processes callbacks registered via nextTick(), ..."
From Synk - Node.js Event-Loop: How even quick Node.js async functions can block the Event-Loop, starve I/O which reference the article above
So the difference between setTimeout, setImmediate and nextTick is:
setTimeout schedules a script to be run after a minimum threshold in ms has elapsed.1
setImmediate runs after the poll phase (the pool phase is the IO events queue in the diagram)
nextTick runs between phases.
1 The order in which the timers are executed will vary depending on the context in which they are called., see here for more
Simple answer:
setImmediate runs on the next tick.
Details:
setImmediate and setTimeout both run in different phases on the event loop.
That is why when setTimeout is set with zero delay it will not run immediately. Use setImmediate which always run on the next tick of the event loop.
but
process.nextTick basically does not care about phases of event loop. The callback you assign to this method will get executed after the current operation is complete and before event loop continues.
The document you linked has a very good explanation about the differences. I'll just grab your attention to few points here.
In setimmediate-vs-settimeout the order of call is nondeterministic UNLESS they are scheduled within an I/O cycle like below example.
Now add the process.nextTick to the example
const fs = require('fs');
// I/O cycle
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
});
process.nextTick(() => {
console.log('nextTick')
})
Output:
nextTick
immediate
timeout
If you run the above code whatever is in process.nextTick function will get executed first. The reason is, it runs before event loop continues. Remember, both setTimeout and setImmediate are event loop related but not process.nextTick.
Be very careful how you use the process.nextTick. You can end up in bad situations if you are not using it properly.
The concept of tick is IMO out of scope for us as JS engineers, as there is no native API for us to find or count which tick we are in right now. Sometimes the poll phase waits for the incoming requests to be completed and the event loop stays in the same tick. However, we can indeed try and make sense of the concept with proper code examples.
I asked the same question on the official node.js dev doc and they haven't gotten back to me yet https://github.com/nodejs/nodejs.dev/issues/2343.
Based on the code I ran and observed, the documentation doesn't really explain it clearly. But here it goes:
setImmediate runs on the next tick of the event loop in the main module. Eg: The initial code from index.js/main.js.
// Both of the codes will be executed in the next tick of the event loop.
// Depending on the event-loop start time, if the timer is executed in the next tick, then setImmediate will also do the same, as the check-phase follows the timers phase.
// If the timer is delayed further then only setImmediate will be executed in the next tick and the timer a tick after that.
setTimeout(() => console.log('May be I run first'), 0);
setImmediate(() => console.log('May be I run first'));
setImmediate runs on the same iteration of the event loop inside an I/O callback. Because timer callbacks are always executed after setImmediate callbacks.
fs.read('/file/path', () => {
// check phase follows the I/O phase and poll phase.
// And when the poll phase is idle then the check phase is run right after.
setImmediate(() => console.log('I am printed first always'));
// Timers will be deferred to the next tick as timers-phase are the start of a "tick".
setTimeout(() => console.log('I will be called in the next tick'), 0);
setTimeout(() => console.log('I will be called may be tick after next one'), 100);
});

How do I wait for a setTimeout in the exit callback for proccess using node?

I have the following code...
async function finish(){
console.log("Finishing");
console.time("fin");
let test = await new Promise(function(res){
setTimeout(()=>{res(test)}, 2000);
});
console.timeEnd("fin");
console.log(test);
};
process.on('exit', finish);
I would expect this to wait two second on exit and print out a timestamp close to 2s. However, when I run the timestamp is shorter and doesn't print any line after Finishing.
How do I wait for a timeout on exit?
From the node docs, you cannot use asynchronous code in the exit event.
Listener functions must only perform synchronous operations. The Node.js process will exit immediately after calling the 'exit' event listeners causing any additional work still queued in the event loop to be abandoned.
If you want to schedule additional work before exiting (e.g. your asynchronous function), you need to use beforeExit.
process.on('beforeExit', finish);
Having said that, you'll also need to recognize that beforeExit is only emitted when the process is out of work to do, so a) it'll not emit if something explicitly calls for termination (e.g. process.exit()) and b) it'll keep emitting unless that happens.

Why node js doesn't exit after promise call

In the following code:
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
sleep(10000);
Why NodeJS doesn't exit immediately? What causes the Promise to be waited for?
I thought I needed await sleep(10000) - but this gives an error.
Nodejs waits for timers that are still active before exiting. You can tell it to NOT wait for a timer by calling .unref() on the timer object itself.
So, it's not actually the promise it is waiting for, but rather the timer it is waiting for.
Internally, node.js keeps a reference count of the number of open timers that have not been .unref() and will not exit until that count (among other things) gets to zero.
Here's a couple excerpts from the node.js doc for timers:
Class: Timeout
By default, when a timer is scheduled using either setTimeout() or setInterval(), the Node.js event loop will continue running as long as the timer is active. Each of the Timeout objects returned by these functions export both timeout.ref() and timeout.unref() functions that can be used to control this default behavior.
timeout.unref()
When called, the active Timeout object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the Timeout object's callback is invoked. Calling timeout.unref() multiple times will have no effect.
Take a look at the unref() function for timers in node - https://nodejs.org/api/timers.html#timers_timeout_unref
When called, the active Timeout object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the Timeout object's callback is invoked.
You can create a timeout and call the unref() function on it - this will prevent node from staying alive if the only thing it is waiting for is the timeout.
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms).unref();
});
}
As a side note, the same unref function can also be used for setTimeout calls.
As correctly noted by jfriend00, it is not the promise that is keeping node alive, it is the timeout.

How to know when the Promise is actually resolved in Node.js?

When we are using Promise in nodejs, given a Promise p, we can't know when the Promise p is actually resolved by logging the currentTime in the "then" callback.
To prove that, I wrote the test code below (using CoffeeScript):
# the procedure we want to profile
getData = (arg) ->
new Promise (resolve) ->
setTimeout ->
resolve(arg + 1)
, 100
# the main procedure
main = () ->
beginTime = new Date()
console.log beginTime.toISOString()
getData(1).then (r) ->
resolveTime = new Date()
console.log resolveTime.toISOString()
console.log resolveTime - beginTime
cnt = 10**9
--cnt while cnt > 0
return cnt
main()
When you run the above code, you will notice that the resolveTime (the time your code run into the callback function) is much later than 100ms from the beginTime.
So If we want to know when the Promise is actually resolved, HOW?
I want to know the exact time because I'm doing some profiling via logging. And I'm not able to modify the Promise p 's implementation when I'm doing some profiling outside of the black box.
So, Is there some function like promise.onUnderlyingConditionFulfilled(callback) , or any other way to make this possible?
This is because you have a busy loop that apparently takes longer than your timer:
cnt = 10**9
--cnt while cnt > 0
Javascript in node.js is single threaded and event driven. It can only do one thing at a time and it will finish the current thing it's doing before it can service the event posted by setTimeout(). So, if your busy loop (or any other long running piece of Javascript code) takes longer than you've set your timer for, the timer will not be able to run until this other Javascript code is done. "single threaded" means Javascript in node.js only does one thing at a time and it waits until one thing returns control back to the system before it can service the next event waiting to run.
So, here's the sequence of events in your code:
It calls the setTimeout() to schedule the timer callback for 100ms from now.
Then you go into your busy loop.
While it's in the busy loop, the setTimeout() timer fires inside of the JS implementation and it inserts an event into the Javascript event queue. That event can't run at the moment because the JS interpreter is still running the busy loop.
Then eventually it finishes the busy loop and returns control back to the system.
When that is done, the JS interpreter then checks the event queue to see if any other events need servicing. It finds the timer event and so it processes that and the setTimeout() callback is called.
That callback resolves the promise which triggers the .then() handler to get called.
Note: Because of Javascript's single threaded-ness and event-driven nature, timers in Javascript are not guaranteed to be called exactly when you schedule them. They will execute as close to that as possible, but if other code is running at the time they fire or if their are lots of items in the event queue ahead of you, that code has to finish before the timer callback actually gets to execute.
So If we want to know when the Promise is actually resolved, HOW?
The promise is resolved when your busy loop is done. It's not resolved at exactly the 100ms point (because your busy loop apparently takes longer than 100ms to run). If you wanted to know exactly when the promise was resolved, you would just log inside the setTimeout() callback right where you call resolve(). That would tell you exactly when the promise was resolved though it will be pretty much the same as where you're logging now. The cause of your delay is the busy loop.
Per your comments, it appears that you want to somehow measure exactly when resolve() is actually called in the Promise, but you say that you cannot modify the code in getData(). You can't really do that directly. As you already know, you can measure when the .then() handler gets called which will probably be no more than a couple ms after resolve() gets called.
You could replace the promise infrastructure with your own implementation and then you could instrument the resolve() callback directly, but replacing or hooking the promise implementation probably influences the timing of things even more than just measuring from the .then() handler.
So, it appears to me that you've just over-constrained the problem. You want to measure when something inside of some code happens, but you don't allow any instrumentation inside that code. That just leaves you with two choices:
Replace the promise implementation so you can instrument resolve() directly.
Measure when .then() is triggered.
The first option probably has a heisenberg uncertainty issue in that you've probably influenced the timing by more than you should if you replace or hook the promise implementation.
The second option measures an event that happens just slightly after the actual .resolve(). Pick which one sounds closest to what you actually want.

the difference between `setTimeout` and `setImmediate`

the nodejs document say
Schedules "immediate" execution of callback after I/O events' callbacks and before timers set by setTimeout and setInterval are triggered. Returns an immediateObject for possible use with clearImmediate.
but I write a test code as follows:
server = http.createServer((req, res)->
res.end()
)
setImmediate(()->
console.log 'setImmediate'
)
setTimeout(()->
console.log 'setTimeout'
, 0)
process.nextTick(()->
console.log 'nextTick'
)
server.listen(8280, ()->
console.log 'i/o event'
)
why the setTimeout always output befeore setImmediate
SetTimeOut - This type of function will be call after set time which is 0 in your case but it follows event loop. And event loop does not grantee that it will work after 0 seconds. In fact it only guarantees that function will be called after completing set time.
But, function can be called any time after completing time when node event queue is free to take up callback function
Source to understand event loop - https://www.youtube.com/watch?v=8aGhZQkoFbQ
SetImmediate - This will get called as and when it goes to stack and does not follow cycle of callback in event loop.
The main advantage to using setImmediate() over setTimeout() is setImmediate() will always be executed before any timers if scheduled within an I/O cycle, independently of how many timers are present.
However, if executed in the main module, the execution order will be nondeterministic and dependent on the performance of the process
see https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/ for more information

Resources