I'm very confused about the differences between nextTick and setImmediate. I've read all the documentation about them on the internet but I still don't understand how they work.
Examples:
function log(n) { console.log(n); }
setImmediate
setImmediate(function() {
setImmediate(function() {
log(1);
setImmediate(function() { log(2); });
setImmediate(function() { log(3); });
});
setImmediate(function() {
log(4);
setImmediate(function() { log(5); });
setImmediate(function() { log(6); });
});
});
//1 2 3 4 5 6
nextTick
process.nextTick(function() {
process.nextTick(function() {
log(1);
process.nextTick(function() { log(2); });
process.nextTick(function() { log(3); });
});
process.nextTick(function() {
log(4);
process.nextTick(function() { log(5); });
process.nextTick(function() { log(6); });
});
});
//1 4 2 3 5 6
Why these results? Please explain with a visual or very easy to follow explanation. Even the node core devs don't agree at how nextTick and setImmediate should be understood by people.
Sources:
setImmediate vs. nextTick
Why is setImmediate much more slower than nextTick?
setImmediate is not always very immediate
Consider the following two examples:
setImmediate
setImmediate(function A() {
setImmediate(function B() {
log(1);
setImmediate(function D() { log(2); });
setImmediate(function E() { log(3); });
});
setImmediate(function C() {
log(4);
setImmediate(function F() { log(5); });
setImmediate(function G() { log(6); });
});
});
setTimeout(function timeout() {
console.log('TIMEOUT FIRED');
}, 0)
// 'TIMEOUT FIRED' 1 4 2 3 5 6
// OR
// 1 'TIMEOUT FIRED' 4 2 3 5 6
nextTick
process.nextTick(function A() {
process.nextTick(function B() {
log(1);
process.nextTick(function D() { log(2); });
process.nextTick(function E() { log(3); });
});
process.nextTick(function C() {
log(4);
process.nextTick(function F() { log(5); });
process.nextTick(function G() { log(6); });
});
});
setTimeout(function timeout() {
console.log('TIMEOUT FIRED');
}, 0)
// 1 4 2 3 5 6 'TIMEOUT FIRED'
setImmediate callbacks are fired off the event loop, once per iteration in the order that they were queued. So on the first iteration of the event loop, callback A is fired. Then on the second iteration of the event loop, callback B is fired, then on the third iteration of the event loop callback C is fired, etc. This prevents the event loop from being blocked and allows other I/O or timer callbacks to be called in the mean time (as is the case of the 0ms timeout, which is fired on the 1st or 2nd loop iteration).
nextTick callbacks, however, are always fired immediately after the current code is done executing and BEFORE going back to the event loop. In the nextTick example, we end up executing all the nextTick callbacks before ever returning to the event loop. Since setTimeout's callback will be called from the event loop, the text 'TIMEOUT FIRED' will not be output until we're done with every nextTick callback.
According the Node.js doc names of these two function are exactly swapped
setImmediate() (BEST RECOMMENDED)
It's fire first at event queue
process.nextTick() (USE FOR SPECIAL CASES see example later on)
It's fire immediately, It's kinda write an statement more at the end at the current file
If we have this code
setTimeout(function(){
console.log('Hello world 5'); // It's waiting like a normal person at a queue
}, 0);
setImmediate(function(){
console.log('Hello world 4');
// It's like get to last and be take care of first
// but always after of .nextTick and before of setInterval(, 0)
});
process.nextTick(function(){
console.log('Hello world 3'); // It's like be at the bottom at this file
});
console.log('Hello world 1');
console.log('Hello world 2');
A visual explanation as per your request:
Cases for use process.nextTick() when you have to emit and event before to handled it:
const EventEmitter = require('events');
const util = require('util');
function MyEmitter() {
EventEmitter.call(this);
// use nextTick to emit the event once a handler is assigned
process.nextTick(function () {
this.emit('event');
}.bind(this));
}
util.inherits(MyEmitter, EventEmitter);
const myEmitter = new MyEmitter();
myEmitter.on('event', function() {
console.log('an event occurred!');
});
Look at this vide where Philip Roberts give us a great explanation about runtime event loop and look at this online eventloop debugger Live test how event loop works
Source:
https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate
I can't reproduce your results for setImmediate. It should be the same as nextTick (and it is in my tests) since in this situation they do pretty much the same thing. The only reasonable explanation for that is that setImmediate is somehow synchronous, but it is not.
And according to NodeJS documentation the only real difference is that multiple nextTick may fire in one loop iteration (depending on maxTickDepth), while setImmediate fires once per iteration.
Below gives you better clarity.
setImmediate
It's execute a script once the current poll phase completes.
It's a timer module function and timer functions are global, you can call them without require.
It can cleared by clearImmediate().
Set "immediate" execution of the callback after I/O events' callbacks before setTimeout() and setInterval().
nextTick
It's a process global object function of NodeJS.
All callbacks passed to process.nextTick() will be resolved before the event loop continues.
Allow users to handle errors.
Helps to try the request again before the event loop continues.
Simple code Snippet.
console.log("I'm First");
setImmediate(function () {
console.log('Im setImmediate');
});
console.log("I'm Second");
process.nextTick(function () {
console.log('Im nextTick');
});
console.log("I'm Last");
/*
Output
$ node server.js
I'm First
I'm Second
I'm Last
Im nextTick
Im setImmediate
*/
I think all the answers above are obsolete, because I got different answers constantly with the current version of nodejs and it is easy to reason about
var log=console.log
log(process.version)
var makeAsyncCall
if(false)
makeAsyncCall=setImmediate
else
makeAsyncCall=process.nextTick;
makeAsyncCall(function A () {
makeAsyncCall(function B() {
log(1);
makeAsyncCall(function C() { log(2); });
makeAsyncCall(function D() { log(3); });
});
makeAsyncCall(function E() {
log(4);
makeAsyncCall(function F() { log(5); });
makeAsyncCall(function G() { log(6); });
});
});
//1
//4
//2
//3
//5
//6
//in both case
After reading https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate
let use start from setImmediate we should keep track of the check queue because it is where the setImmediate callback reside.
First iteration
A is push to check queue
check queue :[A]
Second iteration
A is pull out from queue to execute
During its execution ,it put B and E to queueand then, A complete and start next iteration
check queue :[B,E]
Third iteration
pull out B and push C D
check queue :[E,C,D]
Forth iteration
pull out E and push F G
check queue : [C,D,F,G]
Finally
execute the callbacks in the queue sequentially
For nextTick case, the queue works exactly the same way,that is why it produce same result
The different is that :
the nextTickQueue will be processed after the current operation
completes, regardless of the current phase of the event loop
To be clear,the event loop maintain multiple queues and check queue is just one of them,the node will decide which queue to use based on some rules
with process.nextTick however,it is sort of bypassing all the rule and execute the callback in nextTick immediately
Related
My express code:
app.use('/test', async (req, res, next) => {
try {
setTimeout(() => console.log('setTimeout')); // setTimeout (macrotask)
User.findOne().then(user => console.log('user')); // promise (microtask)
console.log('console.log');
} catch (err) {
next(err);
}
});
The console output order is:
console.log
setTimeout
user
Question: Why microtask is executed after macrotask?
For example, in the browser the next code resolves in correct order:
Code:
setTimeout(function timeout() {
console.log(3);
}, 0);
let p = new Promise(function (resolve, reject) {
for (let i = 0; i < 1e10; i++) {}
resolve();
});
p.then(function () {
console.log(2);
});
console.log(1);
Order:
1
2
3
The micro-task needs to be queued before the macro-task has been dequeued off the macro-task queue for it to run first. Since .findOne() takes some time, the micro-task isn't queued until the promise returned by .findOne() resolves, which happens after your setTimeout callback has been added to the macro-task queue, and then dequeue onto the call stack and executed.
Your "working" code is different to your situation in your Node program with .findOne(), since the executor function for the Promise you're creating runs synchronously (in fact you'll see that this code produces 1, 2, 3 in Node as well):
setTimeout(function timeout() { // <--- queue `timeout` callback as a macro-task
console.log(3);
}, 0);
let p = new Promise(function (resolve, reject) { // run this function synchronously
for (let i = 0; i < 1e10; i++) {} // <--- wait here for the loop to complete
resolve();
});
// Only reached once the loop above has complete, as thus, your promise has resolved
p.then(function () { // <--- `p` has resolved, so we queue the function as a micro-task
console.log(2);
});
console.log(1); // <--- add the function to call stack (first log to execute)
Above, while we're executing the script, both the setTimeout callback and the .then() callback are added to their respective task-queues so that once the script has finished executing, the micro-task can be dequeued and put onto the stack, and then the macro-task can be deqeued and put onto the stack.
Your code is different:
/*
setTimeout gets added to the callstack, that spins off an API which after 0 m/s adds your callback to the macro-task queue
*/
setTimeout(() => console.log('setTimeout'));
/*
.findOne() gets added to the call stack, that spins off an API which after N m/s adds the `.then()` callback to the micro-task queue (N > 0)
*/
User.findOne().then(user => console.log('user')); // promise (microtask)
/*
While the above API is working in the background, our script can continue on...
console.log() gets added to the call stack and "console.log" gets logged
*/
console.log('console.log');
Once the script above has finished, the timeout callback is on the macro-task queue, but the .then() callback isn't on the micro-task queue yet, as the query is still being executed in the background. The timeout callback then gets dequeued onto the call stack. After some time, your .then() callback is added to the micro-task queue and executed once the callstack is empty it gets moved from the queue to the stack.
i was learning async library and just tried some codes myself and i am issueing a problem that can`t handle, can you please look at the code down below:)
async.parallel([
function (cb) {
setTimeout(() => {
let a = "asd";
console.log("AAA");
cb(a, null);
}, 2000);
},
function (cb) {
setTimeout( () => {
let b = "dasd";
console.log("BBBBB");
cb(b, null);
}, 5000);
}
], function (error, results) {
console.log("CCC");
console.log("Errors: " + error);
console.log("Results: " + results);
});
I supposed that BBB should NOT output to the screen, but to my surprise it DOES, can you help me understand why?
You are using async.parallel(). All asynchronous tasks will be executed without waiting for each other and the execution order is not guaranteed.
Here's a breakdown on how your script is executed:
Both setTimeout() are set.
2000 milliseconds later, console.log("AAA") and cb(a, null) are called.
cb(a, null) has an error. So the main callback is called, and async.parallel() ends.
But the story does not end here. The second setTimeout() is already set. Calling the main callback will not clear the timeout.
console.log("BBBBB") and cb(b, null) are called. This is why you see the output BBBBB.
Because the main callback is already called, calling cb(b, null) will not do anything.
I have a function tick that I wish to perform repeatedly. Each time tick completes, I want to trigger it again in 3000 ms time. If tick fails, I want to pause for an extra 1000 ms and then try again. I cannot use setInterval because I do not know how long tick will take to complete.
Here is my code for achieving this:
const loop = async () => {
try {
console.log('Starting operation... ');
await tick();
} catch (error) {
console.error(error);
await sleep(1000);
}
setTimeout(loop, 3000);
};
loop();
Unfortunately, this stops working after several days of operation. I think that I am doing something wrong with the stack.
What is the recommended way of running an async operation like this in Node.js?
Your current function runs the loop every 3 seconds no matter if it fails or not.
I rewrote it a bit. This should work
const loop = async () => {
try {
console.log('Starting operation... ');
await tick();
setTimeout(loop, 3000);
} catch (error) {
console.error(error);
setTimeout(loop, 1000);
}
}
loop()
The above code would have the following order:
first run tick()
if tick() succeeds, run loop again in 3 seconds
if tick() fails, run loop again in 1 second
I have a function that does some work. When it is finished it calls the callback. After that I get the 'END' in console. But i need to execute again the same function. How can I do that? Thx.
function start(callback){
//... some work ...
if(work_finished){
callback();
}
}
start(function(){
console.log('END');
});
If your function is asynchronous, you can create a wrapper function and literally just call it again from the callback. Note, without any terminating conditions, this will run forever.
function start(callback){
//... some work ...
if(work_finished){
callback();
}
}
function run() {
start(function(){
console.log('END');
run();
});
}
If your function is not asynchronous, the above operation will eventually cause a stack overflow (due to infinite recursion) so you'd have to have the caller of start() trigger it again:
function start(callback){
//... some work ...
if(work_finished){
callback();
}
// then return true or false depending upon whether you want
// it to keep getting called again
return true;
}
function run() {
var more;
do {
more = start(function(){
console.log('END');
});
} while (more === true);
}
And, if you just want your function called on some regular time interval, you can use setInterval() like this:
// call my function every 5 seconds
var timer = setInterval(function() {
start(function(){
console.log('END');
});
}, 5000);
There are quite a few ways to repeatedly execute functions in node.
Recursive calls
code:
function start(callback){
//... some work ...
if(work_finished){
callback();
// call function again
// should be OK if some work is async so it doesn't
// block the thread
start(callback);
// or schedule to be called at end of event loop
// setImmediate(start, callback);
}
}
start(function(){
console.log('END');
});
Execute function any number of additional times which would require number of calls to be tracked
set the function up on an interval to be called ~n milliseconds
setInterval(start, 1000, callback);
I'm trying to get my head around when to use process.nextTick. Below I'm using async library to control my code flow and was wondering if I should be calling nextTick in the end callback or not.
async.parallel([
function (callback) {
// do something
callback(data);
},
function (callback) {
// do something
callback(data);
}
],
// callback
function (data) {
process.nextTick(function () {
// do something
});
});
Without knowing exactly what your 'do something' is, I don't see any reason that you'd need to use nextTick in this situation. You use nextTick when you have reason to defer execution of a function to the next iteration of the event loop. You might want to read Understanding process.nextTick for more detail.
Also, note that async's parallel task completion callbacks take arguments err, data, so you should be doing:
async.parallel([
function (callback) {
// do something
callback(null, data);
},
function (callback) {
// do something
callback(null, data);
}
],
// callback
function (err, data) {
if (err) throw err;
// do something
});
The major difference being that the final callback is invoked immediately if one of the parallel tasks returns an error (calls callback with a truthy first argument).
My experience is that for async.parallel and other similar functions to work correctly, that you need to make all tasks definitely asynchronous; I love the async lib and it's my #1 choice over promises etc, but there can be some weird behavior if you don't force tasks to be async.
See here:
https://github.com/caolan/async#common-pitfalls-stackoverflow
so it should be:
async.parallel([
function(cb){
process.nextTick(function(){
doSomePotentiallySyncThing(cb);
});
},
function(cb){
process.nextTick(function(){
doSomePotentiallySyncThing(cb);
});
},
function(cb){
definitelyAsync(cb); // if it's **definitely** async, then we don't need process.nextTick
}
], function complete(err, results){
// we are in the final callback
});
I am 99% sure about this.