If i hit /route2 , i get reponse 15s later,but during that time /route1 gives response immediately.
Shouldn't server wait for 15s and then give the response to /route1.
I read https://medium.com/#cinish/nodejs-multiple-client-requests-694d6353218b but could not the idea.
What i understood is as /route2 is hit console P1 then as there is setTimeout() ,put it in external thread,then console P2 then as setTimeout() ,put it in external thread.Now wait for setTimeouts() to finish.
(At this time the event loop must be busy as it waiting for p1 and p2 fulfillment, so it should accept no new client request).
But it does. Why?
app.get("/route1", (req, res) => {
res.send("Route1");
});
app.get("/route2", async (req, res) => {
const p1 = new Promise((resolve, reject) => {
console.log("P1");
setTimeout(() => {
console.log(5);
resolve();
}, 15000);
})
const p2 = new Promise((resolve, reject) => {
console.log("P2")
setTimeout(() => {
console.log(1);
resolve();
}, 1000);
});
const ans = await Promise.all([p1, p2]);
res.send("Route2");
})
setTimeout() is "non-blocking". That means it sets the timer, returns immediately from the setTimeout() and then continues to execute the rest of the code.
So, in your case /route2 creates the two promises, sets two timers and then waits for Promise.all() to finish. At the point it hits the await, your async route handler returns a promise and returns control back to the event loop.
So, as soon as the /route1 request arrives, it's ready to be processed. /route2 is not active until both timers are done.
Then, when the longer timer is ready to fire, the next time the JS interpreter goes back to the event loop to check for anything else to do, it will see that timer, process the timer callback and that timer callback will resolve the p1 promise and then cause the Promise.all() to be resolved.
If i hit /route2 , i get reponse 15s later,but during that time /route1 gives response immediately. Shouldn't server wait for 15s and then give reponse to /route1.
As explained about setTimeout() is non-blocking so while the /route2 handler is waiting for the two timers to fire, nodejs is free to process other events (like the incoming /route1 event).
What i understood is as /route2 is hit console P1 then as there is setTimeout() ,put it in external thread,then console P2 then as setTimeout() ,put it in external thread.Now wait for setTimeouts() to finish.
Timers are not run in external threads. They are a somewhat unique design in the nodejs event loop. Timers are stored in a sorted linked list in the order of when they are due. Each time the JS interpreter gets back to the event loop and gets to the timer section of the event loop, it just checks the front most timer in the linked list to see if its time has arrived. If so, it triggers that event. If not, it just goes and looks for other types of events.
Eventually, if the event loop has nothing to do and goes to sleep, it will sleep for an appropriate time to wake up in time for the next timer scheduled to run (if nothing else wakes it up before that).
(At this time the event loop must be busy as it waiting for p1 and p2 fullfillment,so it should accept no new client request). But it does.Why?
This is your main wrong assumption. At this time, the event loop is entirely free to process other events. The two timers are set and the event loop will run their callbacks when their time is due, but until then the event loop will process any other incoming events like the /route1 request.
Related
The following example is given in a Node.js book:
var open = false;
setTimeout(function() {
open = true
}, 1000)
while (!open) {
console.log('wait');
}
console.log('open sesame');
Explaining why the while loop blocks execution, the author says:
Node will never execute the timeout callback because the event loop is
stuck on this while loop started on line 7, never giving it a chance
to process the timeout event!
However, the author doesn't explain why this happens in the context of the event loop or what is really going on under the hood.
Can someone elaborate on this? Why does node get stuck? And how would one change the above code, whilst retaining the while control structure so that the event loop is not blocked and the code will behave as one might reasonably expect; wait
will be logged for only 1 second before the setTimeout fires and the process then exits after logging 'open sesame'.
Generic explanations such as the answers to this question about IO and event loops and callbacks do not really help me rationalise this. I'm hoping an answer which directly references the above code will help.
It's fairly simple really. Internally, node.js consists of this type of loop:
Get something from the event queue
Run whatever task is indicated and run it until it returns
When the above task is done, get the next item from the event queue
Run whatever task is indicated and run it until it returns
Rinse, lather, repeat - over and over
If at some point, there is nothing in the event queue, then go to sleep until something is placed in the event queue or until it's time for a timer to fire.
So, if a piece of Javascript is sitting in a while() loop, then that task is not finishing and per the above sequence, nothing new will be picked out of the event queue until that prior task is completely done. So, a very long or forever running while() loop just gums up the works. Because Javascript only runs one task at a time (single threaded for JS execution), if that one task is spinning in a while loop, then nothing else can ever execute.
Here's a simple example that might help explain it:
var done = false;
// set a timer for 1 second from now to set done to true
setTimeout(function() {
done = true;
}, 1000);
// spin wait for the done value to change
while (!done) { /* do nothing */}
console.log("finally, the done value changed!");
Some might logically think that the while loop will spin until the timer fires and then the timer will change the value of done to true and then the while loop will finish and the console.log() at the end will execute. That is NOT what will happen. This will actually be an infinite loop and the console.log() statement will never be executed.
The issue is that once you go into the spin wait in the while() loop, NO other Javascript can execute. So, the timer that wants to change the value of the done variable cannot execute. Thus, the while loop condition can never change and thus it is an infinite loop.
Here's what happens internally inside the JS engine:
done variable initialized to false
setTimeout() schedules a timer event for 1 second from now
The while loop starts spinning
1 second into the while loop spinning, the timer is ready to fire, but it won't be able to actually do anything until the interpreter gets back to the event loop
The while loop keeps spinning because the done variable never changes. Because it continues to spin, the JS engine never finishes this thread of execution and never gets to pull the next item from the event queue or run the pending timer.
node.js is an event driven environment. To solve this problem in a real world application, the done flag would get changed on some future event. So, rather than a spinning while loop, you would register an event handler for some relevant event in the future and do your work there. In the absolute worst case, you could set a recurring timer and "poll" to check the flag ever so often, but in nearly every single case, you can register an event handler for the actual event that will cause the done flag to change and do your work in that. Properly designed code that knows other code wants to know when something has changed may even offer its own event listener and its own notification events that one can register an interest in or even just a simple callback.
This is a great question but I found a fix!
var sleep = require('system-sleep')
var done = false
setTimeout(function() {
done = true
}, 1000)
while (!done) {
sleep(100)
console.log('sleeping')
}
console.log('finally, the done value changed!')
I think it works because system-sleep is not a spin wait.
There is another solution. You can get access to event loop almost every cycle.
let done = false;
setTimeout(() => {
done = true
}, 5);
const eventLoopQueue = () => {
return new Promise(resolve =>
setImmediate(() => {
console.log('event loop');
resolve();
})
);
}
const run = async () => {
while (!done) {
console.log('loop');
await eventLoopQueue();
}
}
run().then(() => console.log('Done'));
Node is a single serial task. There is no parallelism, and its concurrency is IO bound. Think of it like this: Everything is running on a single thread, when you make an IO call that is blocking/synchronous your process halts until the data is returned; however say we have a single thread that instead of waiting on IO(reading disk, grabbing a url, etc) your task continues on to the next task, and after that task is complete it checks that IO. This is basically what node does, its an "event-loop" its polling IO for completion(or progress) on a loop. So when a task does not complete(your loop) the event loop does not progress. To put it simply.
because timer needs to comeback and is waiting loop to finish to add to the queue, so although the timeout is in a separate thread, and may indeed finsihed the timer, but the "task" to set done = true is waiting on that infinite loop to finish
var open = false;
const EventEmitter = require("events");
const eventEmitter = new EventEmitter();
setTimeout(function () {
open = true;
eventEmitter.emit("open_var_changed");
}, 1000);
let wait_interval = setInterval(() => {
console.log("waiting");
}, 100);
eventEmitter.on("open_var_changed", () => {
clearInterval(wait_interval);
console.log("open var changed to ", open);
});
this exemple works and you can do setInterval and check if the open value changed inside it and it will work
Please see below code:
Promise.resolve().then(() => console.log("promise1 resolved"));
Promise.resolve().then(() => console.log("promise2 resolved"));
Promise.resolve().then(() => {
console.log("promise3 resolved");
process.nextTick(() => {
console.log("Inner Next tick");
});
});
Promise.resolve().then(() => console.log("promise4 resolved"));
setImmediate(() => console.log("set immediate1"));
setImmediate(() => console.log("set immediate2"));
process.nextTick(() => console.log("next tick1"));
process.nextTick(() => console.log("next tick2"));
setTimeout(() => console.log("set timeout"), 0);
Output of this code is:
next tick1
next tick2
promise1 resolved
promise2 resolved
promise3 resolved
promise4 resolved
Inner Next tick
set timeout
set immediate1
set immediate2
What i cannot understand is why is the callback for innerTextTick i.e console.log("Inner Next tick") executed before setTimeout.
As per my understanding, first the nextTick queue will be executed, nextTick 1 and 2, then all the resolved Promises and then to the timers phase, which happens as expected. But in the thid promise, i have registered a new callBack in the nextTick queue which should be called after the event loop reaches the nextTick queue again, i.e after the timers phase.
But why does the event loop go back from the promise microtask queue instead of proceeding to the next phase, i.e the timers queue.
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/#process-nexttick:
You may have noticed that process.nextTick() was not displayed in
the diagram, even though it's a part of the asynchronous API. This is
because process.nextTick() is not technically part of the event
loop. Instead, the nextTickQueue will be processed after the current
operation is completed, regardless of the current phase of the event
loop. Here, an operation is defined as a transition from the
underlying C/C++ handler, and handling the JavaScript that needs to be
executed.
Looking back at our diagram, any time you call process.nextTick() in
a given phase, all callbacks passed to process.nextTick() will be
resolved before the event loop continues.
Because in the global scope of main executed file, the Event Loop doesn't come into play yet. All the Promise.resolve() in global goes into MicrotaskQueue and all global nextTick goes into nextTick queue. So your inner nextTick goes into the nextTick queue before the Timeouts Phase of the Event Loop run for the first time. That's also why promise4 resolved even before Inner Next Tick too.
I'm struggled to understand how crypto's result returned before nextTick, Immediate or timeout.
I know this is synchronous crypto so it block the event loop, but how exactly it block when others function got called first and time to finish is faster than cryto?
The order of code line here is not important?
const fs = require('fs');
const crypto = require('crypto');
const start = Date.now();
setTimeout(() => console.log('Timer 1 finished'), 0);
setImmediate(() => console.log('Immediate 1 finished'));
fs.readFile('test-file.txt', () => {
console.log('Reading file.... and finished');
console.log('-----------------');
setTimeout(() => console.log('Timer 2 finished'), 0);
setTimeout(() => console.log('Timer 3 finished'), 2000);
setImmediate(() => console.log('Immediate 2 finished'));
process.nextTick(() => console.log('Process nextTick'));
crypto.pbkdf2Sync('password', 'salt', 100000, 1024, 'sha512');
console.log(Date.now() - start, 'Password encrypted');
crypto.pbkdf2Sync('password', 'salt', 100000, 1024, 'sha512');
console.log(Date.now() - start, 'Password encrypted');
crypto.pbkdf2Sync('password', 'salt', 100000, 1024, 'sha512');
console.log(Date.now() - start, 'Password encrypted');
crypto.pbkdf2Sync('password', 'salt', 100000, 1024, 'sha512');
console.log(Date.now() - start, 'Password encrypted');
});
Result
Timer 1 finished
Immediate 1 finished
Reading file.... and finished
-----------------
2003 'Password encrypted'
3980 'Password encrypted'
5961 'Password encrypted'
7961 'Password encrypted'
Process nextTick
Immediate 2 finished
Timer 2 finished
Timer 3 finished
Why crypto.pbkdf2Sync get executed before setTimeout() in Node JS?
In a nushell, because crypto.pbkdf2Sync() is synchronous and node.js must complete all synchronous code in the current event processing before it can process the completion of any other asycnhronous operations.
setTimeout(), setImmediate() and process.nextTick() all schedule their callback for a FUTURE tick of the event loop. When it's their turn to run, they insert a callback into the event queue. But, NOTHING in the event queue gets to run until the current piece of Javascript is done executing. So, that means that ALL the synchronous code in your fs.readFile() callback runs to completion before anything else can be pulled from the event queue and run.
This sequencing is all because of the "event-driven" nature of node.js. Asynchronous operations always complete on a future tick of the event loop, thus any synchronous code that is already in the process of running must complete before any asynchronous operation can get its completion callback called, even if the asynchronous operation is of the "very-soon" types such as setTimeout(..., 0), process.nextTick() or .setImmediate().
So, the sequence of events goes like this (ignoring the things before fs.readFile() as they aren't relevant since they both occur before the fs.ReadFile() callback completes.
Call fs.readFile(). It starts the file operation and immediately returns.
Node.js goes back to event loop and waits for the next event.
fs.feadFile() completes and inserts a completion callback event in the event queue.
When the interpreter has finished anything else it was running, it grabs the next event from the event queue and calls the fs.feadFile() callback.
setTimeout(..., 0) is called. That schedules a timer event for the next tick of the event loop.
setTimeout(..., 2000) is called. That schedules a timer event for 2 seconds from now.
setImmediate(...) is called. That schedules an event for a future tick of the event loop.
crypto.pbkdf2Sync(...) is called. This is a synchronous operation so it runs immediately and then finishes.
crypto.pbkdf2Sync(...) is called. This is a synchronous operation so it runs immediately and then finishes.
crypto.pbkdf2Sync(...) is called. This is a synchronous operation so it runs immediately and then finishes.
crypto.pbkdf2Sync(...) is called. This is a synchronous operation so it runs immediately and then finishes.
The callback for fs.readFile() finishes. The JS interpreter then pulls the next event from the event queue.
Based on the circumstances and the relevant priority of various types of events, the next item pulled from the event queue is the process.nextTick() callback.
Then, the setImmediate() event.
Then, the setTimeout(..., 0).
Then, after some delay, the setTimeout(..., 2000).
The following example is given in a Node.js book:
var open = false;
setTimeout(function() {
open = true
}, 1000)
while (!open) {
console.log('wait');
}
console.log('open sesame');
Explaining why the while loop blocks execution, the author says:
Node will never execute the timeout callback because the event loop is
stuck on this while loop started on line 7, never giving it a chance
to process the timeout event!
However, the author doesn't explain why this happens in the context of the event loop or what is really going on under the hood.
Can someone elaborate on this? Why does node get stuck? And how would one change the above code, whilst retaining the while control structure so that the event loop is not blocked and the code will behave as one might reasonably expect; wait
will be logged for only 1 second before the setTimeout fires and the process then exits after logging 'open sesame'.
Generic explanations such as the answers to this question about IO and event loops and callbacks do not really help me rationalise this. I'm hoping an answer which directly references the above code will help.
It's fairly simple really. Internally, node.js consists of this type of loop:
Get something from the event queue
Run whatever task is indicated and run it until it returns
When the above task is done, get the next item from the event queue
Run whatever task is indicated and run it until it returns
Rinse, lather, repeat - over and over
If at some point, there is nothing in the event queue, then go to sleep until something is placed in the event queue or until it's time for a timer to fire.
So, if a piece of Javascript is sitting in a while() loop, then that task is not finishing and per the above sequence, nothing new will be picked out of the event queue until that prior task is completely done. So, a very long or forever running while() loop just gums up the works. Because Javascript only runs one task at a time (single threaded for JS execution), if that one task is spinning in a while loop, then nothing else can ever execute.
Here's a simple example that might help explain it:
var done = false;
// set a timer for 1 second from now to set done to true
setTimeout(function() {
done = true;
}, 1000);
// spin wait for the done value to change
while (!done) { /* do nothing */}
console.log("finally, the done value changed!");
Some might logically think that the while loop will spin until the timer fires and then the timer will change the value of done to true and then the while loop will finish and the console.log() at the end will execute. That is NOT what will happen. This will actually be an infinite loop and the console.log() statement will never be executed.
The issue is that once you go into the spin wait in the while() loop, NO other Javascript can execute. So, the timer that wants to change the value of the done variable cannot execute. Thus, the while loop condition can never change and thus it is an infinite loop.
Here's what happens internally inside the JS engine:
done variable initialized to false
setTimeout() schedules a timer event for 1 second from now
The while loop starts spinning
1 second into the while loop spinning, the timer is ready to fire, but it won't be able to actually do anything until the interpreter gets back to the event loop
The while loop keeps spinning because the done variable never changes. Because it continues to spin, the JS engine never finishes this thread of execution and never gets to pull the next item from the event queue or run the pending timer.
node.js is an event driven environment. To solve this problem in a real world application, the done flag would get changed on some future event. So, rather than a spinning while loop, you would register an event handler for some relevant event in the future and do your work there. In the absolute worst case, you could set a recurring timer and "poll" to check the flag ever so often, but in nearly every single case, you can register an event handler for the actual event that will cause the done flag to change and do your work in that. Properly designed code that knows other code wants to know when something has changed may even offer its own event listener and its own notification events that one can register an interest in or even just a simple callback.
This is a great question but I found a fix!
var sleep = require('system-sleep')
var done = false
setTimeout(function() {
done = true
}, 1000)
while (!done) {
sleep(100)
console.log('sleeping')
}
console.log('finally, the done value changed!')
I think it works because system-sleep is not a spin wait.
There is another solution. You can get access to event loop almost every cycle.
let done = false;
setTimeout(() => {
done = true
}, 5);
const eventLoopQueue = () => {
return new Promise(resolve =>
setImmediate(() => {
console.log('event loop');
resolve();
})
);
}
const run = async () => {
while (!done) {
console.log('loop');
await eventLoopQueue();
}
}
run().then(() => console.log('Done'));
Node is a single serial task. There is no parallelism, and its concurrency is IO bound. Think of it like this: Everything is running on a single thread, when you make an IO call that is blocking/synchronous your process halts until the data is returned; however say we have a single thread that instead of waiting on IO(reading disk, grabbing a url, etc) your task continues on to the next task, and after that task is complete it checks that IO. This is basically what node does, its an "event-loop" its polling IO for completion(or progress) on a loop. So when a task does not complete(your loop) the event loop does not progress. To put it simply.
because timer needs to comeback and is waiting loop to finish to add to the queue, so although the timeout is in a separate thread, and may indeed finsihed the timer, but the "task" to set done = true is waiting on that infinite loop to finish
var open = false;
const EventEmitter = require("events");
const eventEmitter = new EventEmitter();
setTimeout(function () {
open = true;
eventEmitter.emit("open_var_changed");
}, 1000);
let wait_interval = setInterval(() => {
console.log("waiting");
}, 100);
eventEmitter.on("open_var_changed", () => {
clearInterval(wait_interval);
console.log("open var changed to ", open);
});
this exemple works and you can do setInterval and check if the open value changed inside it and it will work
I am new to node.js and little bit confused on understanding the event-loop. As far as i know from https://github.com/nodejs/node/blob/master/doc/topics/event-loop-timers-and-nexttick.md, the event-loop phases only process setTimeout, setInterval, setImmediate, process.nextTick, promises and some I/O callbacks.
My question is, if i have following code:
for (var i = 0; i < 100000000; i++)
;
in which phase the above code will get executed ?
Regular JavaScript code, like the for loop in your example, is executed before the queues are cleared. The first thing node will do is run your code, and will only call callbacks, timeout results, I/O results, and so on after your code finishes.
As an example, you could try this code:
fs.open('filename', 'r', () => {
console.log('File opened.');
});
for (var i = 0; i < 100000000; i++);
console.log('Loop complete.');
No matter how big or small your loop variable, 'Loop complete' will always appear before 'File opened'. This is because with only one thread, node can't run the callback you've supplied to the fs.open function until the loop code has finished.
Remember that there isn't a "main" thread that node keeps going back to. Most long-running node programs will run through the code in main.js pretty quickly, and subsequent code is all going to come from callbacks. The purpose of the initial execution is to define how and when those callbacks happen.
In the node event loop doc (https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick), the following code is given as an example:
const fs = require('fs');
function someAsyncOperation(callback) {
// Assume this takes 95ms to complete
fs.readFile('/path/to/file', callback);
}
const timeoutScheduled = Date.now();
setTimeout(() => {
const delay = Date.now() - timeoutScheduled;
console.log(`${delay}ms have passed since I was scheduled`);
}, 100);
// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(() => {
const startCallback = Date.now();
// 10ms loop
while (Date.now() - startCallback < 10) {
// do nothing
}
});
The loop keeps scanning according to phases and after fs.readFile() finishes, the poll queue is is empty, so its callback will be added and immediately executed. The callback holds a blocking 10ms loop before the timer is executed. That is why the delay will display:
105ms have passed since I was scheduled instead of the 100ms you might expect.
Most of your code will live in callbacks so will be executed in the poll phase. If not, like in your example, it will be executed before entering any phases as it will block the event loop.
The caveat are callbacks scheduled by setImmediate that will enter the check phase before resuming the poll phase in the next loop.