The JS Event Loop
Asynchronous events and non-blocking I/O
Node is a JavaScript interpreter for running apps outside the browser (like on a server, for example). It uses non-blocking I/O and asynchronous events, and each module is created within its own filed with an isolated scope. These are fundamental concepts to understand before being able to make Node interpretation work in the intended way, so in this post I'll go through each of these statements and walk through a few examples to illustrate.
Non-blocking I/O
From operations on the database, HTTP requests, and reading/writing to disc, pretty much all input and output in Javascript is non-blocking. By that, I mean that there is a single stream of operations for the interpreter to execute. I imagine them to be like a queue of people waiting in line, each waiting for the interpreter to perform their operation, and chained together through callback functions. After each operation completes, a message is enqueued along with the provided callback function. Later down the track the message is dequeued and the callback fired.
For example:
request('http://www.youtube.com', function(error, response, body) {
console.log(body);
});
console.log('Done!');
Here, you might expect that the request function to google.com is executed, outputting its body to the console, and then 'Done!' is output to the console. Instead what happens is that while the request function is executed first, it passes an anonymous function as a callback to execute when a response is available. “Done!” is immediately output to the console, and then sometime in the future, the response comes back and the callback is executed, outputting its body to the console.
The Event Loop
It's important to understand how the runtime stores these callbacks and in what order they are executed. Conceptually, JavaScript runtime environments use a queue and a loop. The queue stores the list of messages to be processed along with their provided callback functions. The messages are added to the queue in response to certain external events like clicks / HTTP requests.For example, let's say that an event listener is set up to change the font colour of a page when a certain button is clicked. When the button is clicked, the message is enqueued, and enters into the event loop, which follows the pattern:
while there are messages in the queue do
dequeue the first message
execute its callback // the font colour changes
Another interesting example is using setTimeout, which by nature is asynchronous, so the provided callback will be executed as part of a different queued message, on a future run of the event loop.
function apple() {
console.log("an apple a day"); // 1ST
setTimeout(grape, 0);
console.log("keeps the doctor away"); // 2ND
banana();
}
function grape() {
console.log("a bunch of grapes"); //4TH
}
function banana() {
console.log("banana split"); //3RD
}
apple();
In this example, setTimeout is being invoked, passing the callback grape with a timeout of 0 milliseconds. You might be tempted to see the 0 and think that grape will be fired immediately. In reality, because setTimeout is non-blocking, regardless of the specified time (in this case, almost* instantly) a separate message is enqueued containing grape as its callback. 'a bunch of grapes' is logged last, as it has to wait until the next run of the event loop for the callback to the fired.
*the way that setTimeout is usually implemented, it is just meant to execute after a given delay, and once the browser's thread is free to execute it, so even if you say 0 it might not be exactly 0 ms. Unless there's some serious backlog of activity though, a human still won't be able to notice any difference !
One last comment: if in the same call frame two calls are made to setTimeout – passing the same value for a second argument – their callbacks will be queued in the order of invocation.
Summary
With a simple queue and event loop, JavaScript allows us to build systems around a collection of asynchronously-fired callbacks, freeing the runtime to handle concurrent operations while waiting on external events to happen. In the next post I'll walk through the setup of a basic server using node and express.
Checkout the mdn documentation here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop