What is the difference between those two, and when will I use one over the other?
setTimeout is simply like calling the function after delay has finished. Whenever a function is called it is not executed immediately, but queued so that it is executed after all the executing and currently queued eventhandlers finish first. setTimeout(,0) essentially means execute after all current functions in the present queue get executed. No guarantees can be made about how long it could take.
setImmediate is similar in this regard except that it doesn't use queue of functions. It checks queue of I/O eventhandlers. If all I/O events in the current snapshot are processed, it executes the callback. It queues them immediately after the last I/O handler somewhat like process.nextTick. So it is faster.
Also (setTimeout,0) will be slow because it will check the timer at least once before executing. At times it can be twice as slow. Here is a benchmark.
var Suite = require('benchmark').Suite
var fs = require('fs')
var suite = new Suite
suite.add('deffered.resolve()', function(deferred) {
deferred.resolve()
}, {defer: true})
suite.add('setImmediate()', function(deferred) {
setImmediate(function() {
deferred.resolve()
})
}, {defer: true})
suite.add('setTimeout(,0)', function(deferred) {
setTimeout(function() {
deferred.resolve()
},0)
}, {defer: true})
suite
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
.run({async: true})
Output
deffered.resolve() x 993 ops/sec ±0.67% (22 runs sampled)
setImmediate() x 914 ops/sec ±2.48% (57 runs sampled)
setTimeout(,0) x 445 ops/sec ±2.79% (82 runs sampled)
First one gives idea of fastest possible calls. You can check yourself if setTimeout gets called half as many times as other. Also remember setImmediate will adjust to your filesystem calls. So under load it will perform less. I don't think setTimeout can do better.
setTimeout is un-intrusive way of calling functions after some time. Its just like its in the browser. It may not be suited for server-side (think why I used benchmark.js not setTimeout).
A great article about how event loop works and clears some misconceptions.
http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/
Citing the article:
setImmediate callbacks are called after I/O Queue callbacks are finished or timed out. setImmediate callbacks are placed in Check Queue, which are processed after I/O Queue.
setTimeout(fn, 0) callbacks are placed in Timer Queue and will be called after I/O callbacks as well as Check Queue callbacks. As event loop, process the timer queue first in each iteration, so which one will be executed first depends on which phase event loop is.
setImmediate() is to schedule the immediate execution of callback after I/O events callbacks and before setTimeout and setInterval .
setTimeout() is to schedule execution of a one-time callback after delay milliseconds.
This is what the documents say.
setTimeout(function() {
console.log('setTimeout')
}, 0)
setImmediate(function() {
console.log('setImmediate')
})
If you run the above code, the result will be like this... even though the current doc states that "To schedule the "immediate" execution of callback after I/O events callbacks and before setTimeout and setInterval." ..
Result..
setTimeout
setImmediate
If you wrap your example in another timer, it always prints setImmediate followed by setTimeout.
setTimeout(function() {
setTimeout(function() {
console.log('setTimeout')
}, 0);
setImmediate(function() {
console.log('setImmediate')
});
}, 10);
always use setImmediate, unless you are really sure that you need setTimeout(,0) (but I can't even imagine, what for). setImmediate callback will almost always be executed before setTimeout(,0), except when called in first tick and in setImmediate callback.
I think the answer of Navya S is not correct, here is my test code:
let set = new Set();
function orderTest() {
let seq = [];
let add = () => set.add(seq.join());
setTimeout(function () {
setTimeout(function () {
seq.push('setTimeout');
if (seq.length === 2) add();
}, 0);
setImmediate(function () {
seq.push('setImmediate');
if (seq.length === 2) add();
});
}, 10);
}
// loop 100 times
for (let i = 0; i < 100; i++) {
orderTest();
}
setTimeout(() => {
// will print one or two items, it's random
for (item of set) {
console.log(item);
}
}, 100);
The explanations is here
setTimeout(fn,0) can be used for preventing the browser from freezing in massive update. for example in websocket.onmessage, you may have html changes, and if messages keep coming, the browser may freeze when using setImmidiate
To understand them deeply please once go through the event loop phases.
SetImmediate:
It gets executed in the "check" phase. The check phase is called after the I/O phase.
SetTimeOut:
It gets executed in the "timer" phase. The timer phase is the first phase but is called after the I/O phase as well as the Check phase.
To get the output in a deterministic manner, it will depend on which phase the event-loop is; accordingly, we can use the function out of two.
When the Javascript engine starts execution, It checks code line by line.
setTimeout(function() {
console.log('setTimeout')
}, 0)
setImmediate(function() {
console.log('setImmediate')
})
When it comes to
settimeout, it moves from call-stack to call queue and starts a timer for execution.
setimmediate, it moves from call-stack to macro-queue(which is start execution immediately after the first loop is complete)
So, if settimeout value is 0, it will complete its timer before call-stack loop complete.
that's why, settimeout will print before setimmediate.
Now, suppose
setTimeout(function() {
setTimeout(function() {
console.log('setTimeout')
}, 0);
setImmediate(function() {
console.log('setImmediate')
});
}, 10);
This means, first main timeout move to call-queue. meanwhile, call-stack complete its execution.
So, after 10ms, function comes to call stack, it will direct execute setimmediate. Because call-stack is already free to execute task.
use setImmediate() for not blocking the event loop. The callback will run on the next event loop, as soon as the current one is done.
use setTimeout() for controlled delays. The function will run after the specified delay. The minimum delay is 1 millisecond.
Related
I am learning the concept of asynchronous programming in JavaScript (JS). But, I am having a hard time understanding the same. For the last few days, I had been reading various articles on the internet to understand it, but I am unable to grasp the idea.
So, here are the doubts I have:
setTimeout(function(){ alert("Hello 1"); }, 3000); // .....(i)
console.log("Hi!"); // .....(ii)
setTimeout(function(){ alert("Hello 2"); }, 2000); // .....(iii)
Consider the above code. I learnt that JS uses a call-stack and an event-queue to order the execution of instructions. In the above code, when the JS interpreter sees the (i) line, it will enqueue that setTimeout into the event-queue, then moves to (ii), puts it in the call-stack, executes it, then moves to (iii), where it again enqueues the setTimeout into the event-queue (and this queue is not empty), right?
If what I had written in the above question is correct, then once we get to the end of the code since the call-stack is empty the setTimeouts enqueued into the event-queue get executed one by one, right? - That means if we assume it took (say) 10ms to come to the end of the code, then since the event-queue has the setTimeout (i) in the front, it waits for 3s, then pops the alert: "Hello 1", at the time = 3010ms, the dequeues it, and similarly the setTimeout (iii) gets executed after 2 more seconds and then the alert: "Hello 2" pops at the time = 5010ms, right?
Let's suppose that instead of setTimeouts at (i) and (iii), we had addEventListener()'s with some call-back functions. Even in this case, will the call-back functions of the event listeners be enqueued in the event-queue? I feel they don't get enqueued because we could have triggered the call-back of (iii), before the call-back of (i). So, what exactly happens in this case? Is there anything else other than the call-stack and event-queue that somehow stores the information about them and triggers their call-backs accordingly?
In a nut-shell how exactly are the instructions ordered? What exactly happens in the background?
I would be really thankful for a comprehensive answer. It would be great if you can also provide links to some comprehensive materials on this topic.
Thank you for the help!
As you might be aware by now JavaScript engine executes on a single thread, so how are asynchronous operations handled? You are partially true in the below statement, but there is more to it :
Consider the above code. I learnt that JS uses a call-stack and an
event-queue to order the execution of instructions.
True, we do have a call stack and an event loop. But we also have a WEB APIs environment, Call-back Queue and a Micro-task Queue.
Whenever there is any asynchronous task, it moves to the WEB API Environment, for example, when you have an tag with a very large image in the "src" attribute, this image is not downloaded synchronously, because that would block the thread, instead it is moved into the WEB API Environment where the image is loaded.
<img src="largeimg.jpg">
Now, if you want to do something once the image is loaded, you will need to listen to the image's 'load' event.
document.querySelector('img').addEventListener('load', imgLoadCallback);
Now once the image has been loaded, this callback function is still not executed, instead now it is moved into the callback queue. The callback function waits in the callback queue, the event loop will check for synchronous code, and wait until the call stack is empty. Once the call stack is empty, the event loop will push in a first in callback function into the call stack in one event loop tick. And that is when that call back function is executed.
However, this changes when there are micro-tasks such as Promises. When there is a promise, it is sent to the microtask queue. Microtasks will always have priority over the callbacks and they can and will halt the callbacks until they are executed, event loop will always prioritize microtasks.
This is how the JavaScript Call Stack, Event Loop, Call Back Queue, Microtasks Queue and WEB API Environments work.
Now Run this below code, before running try to guess the outcome. It will be exactly as per what I have written above :
//Synchronous Code - Always prioritized over async code
console.log('Asynchronous TEST start');
//It is a 0 Second Timer, But a timer is not a microtask
setTimeout(() => console.log('0 sec timer'), 0);
//Promise is a microtask
Promise.resolve('Resolved promise 1').then(res => console.log(res));
//2nd promise is a microtask too
Promise.resolve('Resolved promise 2').then(res => {
for (let i = 0; i < 1000000000; i++) {} //very large loop
console.log(res);
});
//Synchronous Code - Always prioritized over async code
console.log('Test end');
SPOILER ALERT for above snippet:
As you can see, the timer runs in the end although it is a 0 second timer, it does not actually execute at 0 seconds. Why is that? Because Settimeout uses a callback, and promises are microtasks, Microtask Priority is always greater than Callback Priority
You are correct up until this point:
That means if we assume it took (say) 10ms to come to the end of the code, then since the event-queue has the setTimeout (i) in the front, it waits for 3s, then pops the alert: "Hello 1", at the time = 3010ms
setTimeout will queue the callback to run after a certain time from the moment the setTimeout is called. For example, if setTimeout(fn, 3000) is run, and then 5 seconds of expensive blocking code runs, fn will run immediately after those 5 seconds. If 1 second of blocking code runs instead, fn will run 2 seconds after that blocking code finishes. For example:
console.log('script start');
// Putting the below in a setTimeout so that the above log gets rendered
setTimeout(() => {
setTimeout(() => {
console.log('setTimeout callback');
}, 1000);
const t0 = Date.now();
while (Date.now() - t0 < 700);
console.log('loop done');
}, 30);
Above, you can see that the for loop takes some time to finish, but once it does, the setTimeout callback runs nearly immediately afterwards.
You can think of it like: when setTimeout is called, at Date.now() + delay, a new task gets pushed to the macrotask queue. Other code may be running at the time the task gets pushed, or it may have taken some time before the code after the setTimeout finished, but regardless, the callback will run as soon as it can after Date.now() + delay.
This process is described precisely in the specification:
(After waiting is finished...) Queue a global task on the timer task source given method context to run task.
The task does not exist in the queue (or in the stack) until the time elapses, and the function call only goes into the stack once the task starts running - which may occur as soon as the time elapses, or it may take some additional time if a different task is running at that time.
we had addEventListener()'s with some call-back functions. Even in this case, will the call-back functions of the event listeners be enqueued in the event-queue?
No - their handlers will only get put into the queue once the listener fires.
In node the documentation here, it is said that the output of setTimeout and setImmidiate being called together is non-deterministic.
i understand that,
but what follows it is an example of using an IO wrapper callback
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
});
which makes the order always be:
sesetImmidiate
setTimeout
with the following explanation:
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.
why exactly 'setImmediate() will always be executed before any timers if scheduled within an I/O cycle'?
This is because of libuv design, in this article you can find a complete explanation how this works, here's a summary:
Libuv order execution:
while (r != 0 && loop->stop_flag == 0) {
// first timers
uv__update_time(loop);
uv__run_timers(loop);
ran_pending = uv__run_pending(loop);
uv__run_idle(loop);
uv__run_prepare(loop);
timeout = 0;
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) {
timeout = uv_backend_timeout(loop);
}
uv__io_poll(loop, timeout);
uv__run_check(loop); // check handlers - "setImmediate"
uv__run_closing_handles(loop);
if (mode == UV_RUN_ONCE) {
// second timers
uv__update_time(loop);
uv__run_timers(loop);
}
r = uv__loop_alive(loop);
if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
break;
}
uv__loop_alive — Check whether there are any referenced handlers to be
invoked, or any active operations pending
uv__update_time — This
will send a system call to get the current time and update the loop
time (This is used to identify expired timers).
uv__run_timers — Run
all expired timers
uv__run_pending — Run all completed/errored I/O
callbacks
uv__io_poll — Poll for I/O
uv__run_check — Run all check
handlers (setImmediate callbacks will run here)
uv__run_closing_handles — Run all close handlers
Both setTimeout and setImmediate are macrotasks, here's why are executed in that order, nice discussion about this here:
If scripts have been scheduled by setImmediate(), "polling" phase will
set a time-out which is zero.It means that after the queue has been
exhausted, "polling" phase will not wait for callbacks to be added to
the queue but continue to the check phase.
If scripts have been
scheduled by setTimeout(), "polling" will set a time-out which is the
result of the soonest threshold of timers minus current time.Then when
time out, the loop continues and finally wraps back to the timers
phase.
I have read a lot of related documents.But I still can't understand how it works.
const fs = require('fs')
const now = Date.now();
setTimeout(() => console.log('timer'), 10);
fs.readFile(__filename, () => console.log('readfile'));
setImmediate(() => console.log('immediate'));
while(Date.now() - now < 1000) {
}
const now = Date.now();
setImmediate(() => console.log('immediate'));
setTimeout(() => console.log('timer'), 10);
while(Date.now() - now < 1000) {
}
I think the first piece of code should log:
readfile
immediate
And the second piece of code logs.
timer
immediate
I think it is ok.
Problem:
I don't understand why the first piece of code logs
immediate
readfile
I think that the file has been read completely and its callback function enqueue I/O callbacks phase's queque after 1 second.
And then I think event loop will move to timers(none),I/O callbacks(fs.readFile's callback),idle/prepare(none),poll(none),check(setImmediate's callback)and finally close callbacks(none) in order, but result is that setImmediate() still run first.
The behavior you see is because there are multiple types of queues in the event loop and the system runs events in an order according to their type. It is not just one giant event queue where everything runs in FIFO order based on when it was added to the event queue. Instead, it likes to run all the events of one type (up to a limit), advance to the next type, runs all those and so on.
And, I/O events are only added to their queue at one specific point in the cycle so they are forced into a particular order. This is the reason that setImmediate() callback executes before the readFile() callback even though both are ready to go when the while loop is done.
And then I think event loop will move to timers(none),I/O callbacks(fs.readFile's callback),idle/prepare(none),poll(none),check(setImmediate's callback)and finally close callbacks(none) in order, but result is that setImmediate() still run first.
The issue is that the I/O callbacks stage of the event loop runs I/O callbacks that are already in the event queue, but they don't get put into the event queue automatically when they are done. Instead, they are only put into the event queue later in the process in the I/O poll step (see diagram below). So, the first time through the I/O callbacks stage, there are no I/O callbacks to run yet, thus you don't get the readfile output when you think you would.
But, the setImmediate() callback is ready the first time through the event loop so it gets to run before the readFile() callback.
This delayed addition of I/O callbacks is likely the explanation for why you are surprised that the readFile() callback happens last instead of before the setImmediate() callback.
Here's what happens when the while loop finishes:
When the while loop finishes, it starts with timer callbacks and sees that the timer is ready to run so it runs that.
Then, it goes to run any I/O callbacks that are already there, but there are none yet. The I/O callback from the readFile() has not been collected yet. It will get collected later in this cycle.
Then, it goes through several other stages and gets to I/O poll. There is collects the readFile() callback event and puts it in the I/O queue (but does not run it yet).
Then, it goes to the checkHandlers phase where it runs the setImmediate() callback.
Then, it starts the event loop over again. There are no timers so it goes to I/O callbacks and it finally finds and runs the readFile() callback.
So let's document what actually happens in your code in a little more detail for those that are not as familiar with the event loop process. When you run this code (with timing added to the output):
const fs = require('fs')
let begin = 0;
function log(msg) {
if (!begin) {
begin = Date.now();
}
let t = ((Date.now() - begin) / 1000).toFixed(3);
console.log("" + t + ": " + msg);
}
log('start program');
setTimeout(() => log('timer'), 10);
setImmediate(() => log('immediate'));
fs.readFile(__filename, () => log('readfile'));
const now = Date.now();
log('start loop');
while(Date.now() - now < 1000) {}
log('done loop');
You get this output:
0.000: start program
0.004: start loop
1.004: done loop
1.005: timer
1.006: immediate
1.008: readfile
I've added timing in seconds relative to when the program started so you can see when things are executed.
Here's what happens:
Timer is started and set for 10ms from now, other code continues to run
fs.readFile() operation is started, other code continues to run
setImmediate() is registered into the event system and its event is in the appropriate event queue, other code continues to run
while loop starts looping
During the while loop, the fs.readFile() finishes its work (running in the background). It's event is ready, but not yet in the appropriate event queue (more on this later)
while loop finishes after 1 second of looping and this initial sequence of Javascript is done and returns back to the system
The interpreter now needs to get the "next" event from the event loop. But, all types of events are not treated equally. The event system has a particular order that it processes different types of events in the queue. In our case, here, the timer event gets processed first (I will explain this in the following text). The system checks to see if any timers have "expired" and are ready to call their callback. In this case it finds that our timer has "expired" and is ready to go.
Timer callback is called and we see the console message timer.
There are no more timers so the event loop advances to its next stage. The next stage of the event loop is to run any pending I/O callbacks. But, there are no pending I/O callbacks in the event queue yet. Even though the readFile() is done by now, it is not yet in the queue (explanation coming).
Then, the next step is to gather any I/O events that have finished and get them ready to run. Here, the readFile() event will be collected (though not run yet) and put into the I/O event queue.
Then the next step is to run any setImmediate() handlers that are pending. When it does that, we get the output immediate.
Then, the next step in the event process is to run any close handlers (there are none here to run).
Then, the event loop starts over again by checking for timers. There are no pending timers to run.
Then, the event loop runs any pending I/O callbacks. Here the readFile() callback runs and we see readfile in the console.
The program has no more events to wait for so it executes.
The event loop itself is a series of queues for different types of events and (with some exceptions), each queue is processed before moving onto the next type of queue. This causes groupings of events (timers in one group, pending I/O callbacks in another group, setImmediate() in another group and so on). It is not a strict FIFO queue among all types. Events are FIFO within a group. But, all pending timer callbacks (up to some limit to keep one type of event from hogging the event loop indefinitely) are processed before other types of callbacks.
You can see the basic structure in this diagram:
which comes from this very excellent article. If you really want to understand all this stuff, then read this referenced article several times over.
What initially surprised me is why the readFile always comes at the end. This is because even though the readFile() operation is done, it is not immediately put in the queue. Instead, there's a step in the event loop where completed I/O events are collected (to be processed in the next cycle through the event loop) and setImmediate() events are processed at the end of the current cycle before the I/O events that were just collected. This makes the readFile() callback go after the setImmediate() callback, even though they both are ready to go during the while loop.
And, further, it doesn't matter which order you execute the readFile() and the setImmediate(). Because they both are ready to go before the while loop is done, their execution order is determined by the sequencing though the event loop as it runs different types of events, not by exactly when they finished .
In your second code block, you remove the readFile() and put the setImmediate() before the setTimeout(). Using my timed version, that would be this:
const fs = require('fs')
let begin = 0;
function log(msg) {
if (!begin) {
begin = Date.now();
}
let t = ((Date.now() - begin) / 1000).toFixed(3);
console.log("" + t + ": " + msg);
}
log('start program');
setImmediate(() => log('immediate'));
setTimeout(() => log('timer'), 10);
const now = Date.now();
log('start loop');
while(Date.now() - now < 1000) {}
log('done loop');
And, it generates this output:
0.000: start program
0.003: start loop
1.003: done loop
1.005: timer
1.008: immediate
The explanation is similar (shortened a bit this time since lots of detail was explained earlier).
setImmediate() is registered into the appropriate queue.
setTimeout() is registered into the timer queue.
The while loop runs for its 1000ms
The code finishes executing and returns control back to the system
The system starts at the top of the event logic which starts with timer events. The timer we started earlier is done now so it runs its callback and logs timer.
With no more timers, the event loop runs through several other types of event queues until it gets to where it runs setImmediate() handlers and it logs immediate.
If, you have multiple items schedule to start within an I/O callback such as this:
// timeout_vs_immediate.js
const fs = require('fs');
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
});
Then, you get slightly different behavior because the setTimeout() and setImmediate() will be scheduled when the event loop is in a different part of its cycle. In this particular example, the setImmediate() will always execute BEFORE the timer so the output will be:
immediate
timeout
In the flow chart above, you can see where the "run completed I/O handlers" step is. Because the setTimeout() and setImmediate() calls will be scheduled from within an I/O handler, they are going to be scheduled at the "Run completed I/O handlers" phase of the event loop. Follow the flow of the event loop, the setImmediate() will get serviced in the "check handlers" phase before the event loop gets back around to service timers.
If the setImmediate() and setTimeout() are scheduled at a different point in the event loop, then the timer may fire before setImmediate() which is what happens in the earlier example. So, the relative timing of the two depends upon what phase the event loop is in when the functions are called.
setTimeout(() => console.log('timer'), 10);
fs.readFile(__filename, () => console.log('readfile'));
setImmediate(() => console.log('immediate'));
while(Date.now() - now < 1000) {
}
Explanation
The setTimeout schedules to be put in an event loop after 10ms.
Asynchronous file reading starts.
The non-standard setImmediate schedules to show a console output breaking long processes.
A one-second blocking loop runs. Nothing in the console yet.
setImmediate prints immediate console message during the loop.
File reading ends and the callback is executed even after the while loop is
over. The console output readfile is there now.
Finally, the console message timer is printed after about 10 secs later.
Things to note
None of above commands (except the loop) are synchronous. They
schedule something and immediately proceed to the next command.
The callback functions are called only after the current blocking
execution is over.
Timeout commands are not guaranteed to be executed at the designated
interval. The guarantee is that they will run anytime after the
interval.
setImmediate is very experimental.
Below is the code present in "practise01.js" file,
function fn(name){
return f;
function f(){
var n = name;
console.log("Next TICK "+n+", ");
}
}
function myTimeout(time,msg){
setTimeout(function(){
console.log("TIMEOUT "+msg);
},time);
}
process.nextTick(fn("ONE"));
myTimeout(500,"AFTER-ONE");
process.nextTick(fn("TWO"));
myTimeout(500,"AFTER-TWO");
process.nextTick(fn("THREE"));
myTimeout(500,"AFTER-THREE");
process.nextTick(fn("FOUR"));
The output from running above code is
rahul#rahul:~/myPractise/PlainNodeJSPractise01/Process$ node practise01.js
Next TICK ONE,
Next TICK TWO,
Next TICK THREE,
Next TICK FOUR,
TIMEOUT AFTER-ONE
TIMEOUT AFTER-TWO
TIMEOUT AFTER-THREE
Now I wrote the code without using process.nextTick, in "practise02.js", as follows,
function myTimeout(time,msg){
setTimeout(function(){
console.log("TIMEOUT "+msg);
},time);
}
function fn(name){
return f;
function f(){
var n = name;
console.log("Next TICK "+n+", ");
}
}
fn("ONE")();
myTimeout(500,"AFTER-ONE");
fn("TWO")();
myTimeout(500,"AFTER-TWO");
fn("THREE")();
myTimeout(500,"AFTER-THREE");
fn("FOUR")();
after running the above code the output is
rahul#rahul:~/myPractise/PlainNodeJSPractise01/Process$ node practise02.js
Next TICK ONE,
Next TICK TWO,
Next TICK THREE,
Next TICK FOUR,
TIMEOUT AFTER-ONE
TIMEOUT AFTER-TWO
TIMEOUT AFTER-THREE
If you see both the outputs are same.
So in which case I need to go with process.nextTick ?
When I tried to read more, what I came to understand is If I need to execute some function immediately when the eventloop is empty than go for "process.nextTick".
So how does its different from my second approach.
Please explain me or give me some pointers
The node documentation is actually pretty good in explaining when and why using nextTick:
https://nodejs.org/api/process.html#process_process_nexttick_callback_args
What it does:
This is not a simple alias to setTimeout(fn, 0), it's much more efficient. It runs before any additional I/O events (including timers) fire in subsequent ticks of the event loop.
and when to use:
This is important when developing APIs in order to give users the opportunity to assign event handlers after an object has been constructed but before any I/O has occurred...
function definitelyAsync(arg, cb) {
if (arg) {
process.nextTick(cb);
return;
}
fs.stat('file', cb);
}
definitelyAsync(true, () => {
foo();
});
bar(); // will now allways be called before foo()
First lets understand the behaviour of process.nextTick()
Eventloop has phases where in each phase different type of async functions get executed.
process.nextTick(callback[, ...args]) is a part of the asynchronous API of nodeJS. But it is not technically part of the event loop.
nextTickQueue will be processed after the current operation is completed, regardless of the current phase of the event loop.
any time we call process.nextTick() in a given phase of eventloop, callback passed to process.nextTick() will be resolved before the event loop continues.
Why we need to use process.nextTick
It is very important for APIs to be either 100% synchronous or 100% asynchronous. Consider this example:
// WARNING! DO NOT USE! BAD UNSAFE HAZARD!
function maybeSync(arg, cb) {
if (arg) {
cb();
return;
}
fs.stat('file', cb);
}
const maybeTrue = Math.random() > 0.5;
maybeSync(maybeTrue, () => {
foo();
});
bar();
It is not clear whether foo() or bar() will be called first.
The following approach is much better:
function definitelyAsync(arg, cb) {
if (arg) {
process.nextTick(cb);
return;
}
fs.stat('file', cb);
}
already #Johannes Merz has mentioned in his answer why it's good to use process.nextTick(callback) rather than setTimeout(callback, 0)
For more refer here
You have your answer in your post where you share your output with us in:
rahul#rahul:~/myPractise/PlainNodeJSPractise01/Process$ node practise02.js
Next TICK ONE,
Next TICK TWO,
Next TICK THREE,
Next TICK FOUR,
TIMEOUT AFTER-ONE
TIMEOUT AFTER-TWO
TIMEOUT AFTER-THRE
If we change your timeout interval from 500 to 0 still same result:
function fn(name){
return f;
function f(){
var n = name;
console.log("Next TICK "+n+", ");
}
}
function myTimeout(time,msg){
setTimeout(function(){
console.log("TIMEOUT "+msg);
},time);
}
process.nextTick(fn("ONE"));
myTimeout(0,"AFTER-ONE");// set timeout to execute in 0 seconds for all
process.nextTick(fn("TWO"));
myTimeout(0,"AFTER-TWO");
process.nextTick(fn("THREE"));
myTimeout(0,"AFTER-THREE");
process.nextTick(fn("FOUR"));
Results
Next TICK ONE,
Next TICK TWO,
Next TICK THREE,
Next TICK FOUR,
TIMEOUT AFTER-ONE
TIMEOUT AFTER-TWO
TIMEOUT AFTER-THREE
when you use process.nextTick you basically ensure that the function that you pass as a parameter will be called immediately in the next tick ie. start of next event loop.So that's why all your function in next tick executes before your timer ie. setTimeout next tick doesn't mean next second it means next loop of the nodejs eventloop. Also next tick ensures that the function you are trying to call is executed asynchronously. And next tick has higher priority than your timers, I/O operations etc queued in the eventloop for execution. You should use nextTick when you want to ensure that your code is executed in next event loop instead of after a specified time. nextTick is more efficient than timers and when you want to ensure the function you call is executed asynchronously . You can find more information on this in nodejs docs
I am very new to node.js. Am trying to understand what exactly is meant by 'asynchronous' in terms of node js.
In the above context I have the below code:-
function foo()
{
setImmediate(function two()
{
console.log(1);
});
setTimeout(function one()
{
console.log(3);
},0);
process.nextTick(function three()
{
console.log(2);
});
console.log(4);
}
foo();
can some one please explain me, in depth, as to what exactly would be the order of execution for all of the above timer APIs and WHY will it be so? Any explanations/references regarding the call back stack etc. will also be helpful.
First of all, 4 gets logged first because all other calls to setImmediate, setTimeout or nextTick delay the execution of a function to somewhere after the currently executing code. But they all do it differently:
setTimeout
This function allows you to do something after a specific amout of milliseconds. If the milliseconds you pass to this function are less that 1ms, it will always wait 1ms before calling your function.
setImmediate
This function allows you to do something after node has processed all i/o events. Node processes i/o events in every cycle of the event queue. So setTimeout will always execute your function in the next cycle of the event queue. This allows the queue spin unblocked.
process.nextTick
This function allows you to do something immediately after the currently running code finishes. You can imagine it like you would be able to modify the currently executing code and add some lines after it, so that it does something more before it's finished. Calling this function again and again does block the event loop because it cannot go on to the next task in the queue, since it's still busy with the current one. This means, node does not process the i/o events until the last function you passed to nextTick got executed. Therefore you should never call this function recursively or use it too much, because it can stop the event loop from spinning. Node will display a warning if this happens, though.
So.. to explain the output of 4 2 1 3:
4 is the first log that's not getting delayed and thus is the first output.
2 is getting logged immediately after foo() finishes and thus is the second
3 is faster than 1 because a usual event loop cycle is much faster than 1 millisecond, and so.. 3 is the third log
setTimeout delays by at least 1ms which is the longest delay of all the delay functions. It's clearly the last.