how node handles computation and event loop - node.js

for(var i = 0; i < 100000; i++){
setTimeout(function(){
console.log("Inside")
}, 0);
console.log("Outside")
};
It gives the output:
Outside * 100000
Inside * 100000
why this output?
CPU bound activities are handled in-line, and when all CPU bound activities are over then it processes the event que?

setTimeout() is non-blocking and it calls it's callback asynchronously. That means that setTimeout() runs, schedules a timer for the future and then immediately returns. Then, sometime later, when the timer fires, it inserts an event in the event queue. When the interpreter is done executing other Javascript, it fetches the next event out of the event queue and will then run the timer callback.
So, here's what happens in your code:
Run the body of the for loop 100,000 times and each time through the loop, schedule a timer and then output console.log("Outside").
Then, when the for loop is done and control returns back to the system, check the event queue to see if there is an event.
Because all the timers were set with a timer of 0, there are probably a lot of timer events in the queue. Pull the first event out and runs it's callback which will output console.log("Inside").
Repeat until there are no more events in the event queue (which will take 100,000 iterations to process all the timers you previously set).
There are two keys here:
setTimeout() is "non-blocking". It schedules the timer and immediately returns.
When the timer fires, it inserts an event in the event queue to run the timer callback and that callback will ONLY get called when the JS interpreter is done doing what else it was doing and can then fetch the next event from the event queue.
This means that all synchronous code finishes first before any asynchronous callbacks can be fetched from the event queue and run.

Related

Node.js Event-Loop. Why callbacks from the check queue execute before those from the poll queue while Node.js DOCs state vice versa?

According to the Node.js DOCs,
when the event-loop enters its poll phase and the poll queue is not empty,
the callbacks in the poll queue should get executed before the event-loop
proceeds further to its check phase.
In reality, however, the opposite happens, that is if neither the poll, nor the
check (setImmediate) queue is empty by the time the event-loop is entering
the poll phase, the callbacks from the check (setImmediate) queue always execute
before the callbacks from the poll queue.
Why is that? What am I missing in the Node.js DOCs?
Here follow the sample piece of code and the quotation from the Node.js DOCs.
The quote from the Node.js DOCs:
The poll phase has two main functions:
1. Calculating how long it should block and poll for I/O, then
2. Processing events in the poll queue.
When the event loop enters the poll phase and there are no timers scheduled,
one of two things will happen:
(a) - If the poll queue is not empty, the event loop will iterate
through its queue of callbacks executing them synchronously
until either the queue has been exhausted,
or the system-dependent hard limit is reached.
(b) - If the poll queue is empty, one of two more things will happen:
- If scripts have been scheduled by setImmediate(),
the event loop will end the poll phase and continue to the check phase
to execute those scheduled scripts.
- If scripts have not been scheduled by setImmediate(),
the event loop will wait for callbacks to be added to the queue,
then execute them immediately.
Once the poll queue is empty the event loop will check for timers
whose time thresholds have been reached. If one or more timers are ready,
the event loop will wrap back to the timers phase
to execute those timers' callbacks.
The sample code:
const fs = require(`fs`);
console.log(`START`);
const readFileCallback = () => {
console.log(`readFileCallback`);
};
fs.readFile(__filename, readFileCallback);
const setImmediateCallback = () => {
console.log(`setImmediateCallback`);
};
setImmediate(setImmediateCallback);
// Now follows the loop long enough to give the fs.readFile enough time
// to finish its job and to place its callback (the readFileCallback)
// into the event-loop's poll phase queue before the "main" synchronous part
// of the this code finishes.
for (let i = 1; i <= 10000000000; i++) {}
console.log(`END`);
// So when the event-loop starts its first tick there should be two callbacks
// waiting:
// (1) the readFileCallback (in the poll queue)
// (2) the setImmediateCallback (in the check queue)
// Now according to the Node.js DOCs, of these two waiting callbacks
// the readFileCallback should execute first, but the opposite
// is actually happening, that is setImmediateCallback executes first.

setTimeout(Func, 0) to be executed before setImmediate?

As per my understanding the setImmediate is executed in the Check phase of the event loop. The Poll phase schedules the timers to be executed in the Timers phase if their minimum threshold is elapsed.
But the following code executes the timer callback before the setImmediate one (not always). How is that possible since the timer should be scheduled in the Poll phase and the Check phase comes after it ?
Is it something related to that code is executed in the main module, if so how come setImmediate sometimes executed before the timer ?
setTimeout(function() {
console.log('setTimeout');
}, 0);
setImmediate(function() {
console.log('setImmediate');
});

Understanding Call backs

I create a small script to understand callback better.
From the below script, the behavior I expected was: "http.get runs and takes on average 200 ms. The for loop "i" increment takes on average 2500 ms. At 200 ms, the process should exit and the script should have stopped to work. Why is it printing all of i? If I understand this better, I think I understand callback.
var http = require("http");
var starttime = new Date();
//Function with Callback
for (var j =0; j<10; j++){
http.get({host : 'nba.com'}, function(res){
console.log("Time Taken = ", new Date() - starttime, 'ms');
process.exit();
}).on('error', function(er){
console.log('Got Error :', er.message);
})
}
//Loop that exceeds callback trigger time
for(var i=1; i<10000; i++){
console.log(i);
}
console.log("Time Taken = ", new Date() - starttime, 'ms');
Javascript in node.js is single threaded and I/O is event driven using an event queue. Thus your async callbacks that signal the completion of the http requests cannot run until your original thread of Javascript finishes and returns control back to the system where it can then pull the next event from the event queue to service the completion of the http request.
As such, your for loop will run to completion before any http responses can be processed.
Here's the step by step process:
Your first for loop runs and sends 10 http requests.
These http requests run in the background using async networking. When one of them completes and has a response, the http module will put an event in the Javascript event queue and it will be the JS interpreter's job to pull that event from the event queue when it is finished with its other activities.
Your second for loop runs to completion and all the i values are output to the console.
Your script finishes.
The JS interpreter then checks the event queue to see if there are any pending events. In this case, there will be some http response events. The JS interpreter pulls the oldest event from the event queue and calls the callback associated with that.
When that callback finishes, the next event is pulled from the event queue and the process continues until the event queue is empty.
If any of your callbacks call process.exit(), then this short circuits the remaining callbacks and exits the process immediately.
While this other answer was written for the browser, the event-driven, single threaded concept is the same as it is in node.js so this other answer may explain some more things for you: How does JavaScript handle AJAX responses in the background?

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

async nodejs execution order

When does processItem start executing. Does it start as soon as some items are pushed onto the queue? Or must the for loop finish before the first item on the queue starts executing?
var processItem = function (item, callback) {
console.log(item)
callback();
}
var myQueue = async.queue(processItem, 2)
for (index = 0; index < 1000; ++index) {
myQueue.push(index)
}
The simple answer is that all of your tasks will be added to the queue, and then executed in a random (undefined) order.
background information, via https://github.com/caolan/async#queueworker-concurrency
queue(worker, concurrency)
Creates a queue object with the specified concurrency. Tasks added to the queue are processed in parallel (up to the concurrency limit). If all workers are in progress, the task is queued until one becomes available. Once a worker completes a task, that task's callback is called.
In other words, the order is undefined. If you require the tasks to be executed in a particular order, you should be using a different asynchronous primitive, such as series(tasks, [callback])
https://github.com/caolan/async#seriestasks-callback
The current call stack must resolve before any asynchronous tasks will run. This means that the current function must run to completion (plus any functions that called that function, etc.) before any asynchronous operations will run. To answer your question directly: all items will be fully queued before the first one runs.
It might be helpful for you to read more about the JavaScript event loop: asynchronous jobs sit in the event queue, where they are handled one by one. Each job in the event queue causes the creation of the call stack (where each item in the stack is function call -- the first function is on the bottom, a function called within that first function is next-to-bottom, etc.). When the stack is fully cleared, the event loop processes the next event.

Resources