Event Loop In Node.js
Table of contents
What is an Event loop.
Tasks are executed in Last In First Out order (using a stack data structure) and these tasks are executed synchronously.
For Javascript to execute asynchronous task (tasks that require some amount of time to be executed) the Javascript V8 engine employs the use of the libuv, the libuv API is essentially for running asynchronous tasks.
- How tasks are executed under the hood
All tasks are push into a call stack and then the synchronous are executed first in a LIFO order, during execution it if encounters an asynchronous task, it pushes the task into into the libuv for it be executed and continues it’s execution in the call stack.
When libuv is done resolving the task given to it, it moves the task into the event queue which is then handle by the event loop
- So what is an event loop
The event loop is a mechanism that continuously checks for event in the event queue, if any, it pushes the callback into the call stack and ready to be executed. It is a C program that orchestrates or co-ordinates the execution of synchronous and asynchronous code in Node.js.
The event loop consist of 6 queues and these queues have their order of execution.
Queues in the event loop:
nextTick() queue
promise queue
The above queue group under the microtask queue.
Timer queue
input/output queue
Check queue
6.Closed queue
Order of execution
In the event loop:
All the APIs in the event loop queues executes callback functions
- The microtask queues are always executed first.
The callbacks in the nextTick queue is executed first before the promise queue callbacks.
Promise.resolve().then(() => console.log('Promise callback 1'));
process.nextTick(() => console.log('Process nextTick 1'));
OUTPUT:
Process nextTick 1
Promise callback 1
The timer queues callbacks are executed next and it consists of operations like setTimeout and setInterval API
setTimeout(() => console.log('Inside Timeout')) Promise.resolve().then(() => console.log('Promise callback 1')); process.nextTick(() => console.log('Process nextTick 1')); OUTPUT: Process nextTick 1 Promise callback 1 Inside Timeout
input/Output(I/O) queue consist of operations like reading and writing to a file, using modules like the “fs” module. This queue is executed next after the timer queue
const fs = require('fs') setTimeout(() => console.log('Inside Timeout')) fs.readFile(() => console.log('File read')) OUTPUT: Inside Timeout File read
Check queue consist of the setImmediate API, which always executed after the I/O queue but setImmediate callback always gets executed first due to I/O polling.
I/O events are polled and the callback function are only added to the I/O queue only after the I/O is complete.
const fs = require('fs') fs.readFile(() => console.log('File read')) setImmediate(() => console.log('Inside setImmediate')) OUTPUT: Inside setImmediate File read
Closed Queue are executed last after all other queues in the loop have been executed and it handles the closing of an API resource, like clearing a setTimeout or closing a stream event
const fs = require('fs')
setTimeout(() => console.log('Inside Timeout'))
const readableStream = fs.createReadStream(__filename);
readableStream.close();
// logs to the console last
readableStream.on('close', () => {
console.log('Closing read stream')
})
OUTPUT:
Inside Timeout
Closing read stream
- Conclusion
Understanding the event loop, helps to write more performant Javascript code, especially when dealing with asynchronous tasks.
Subscribe to my newsletter
Read articles from Oluwatobi Akinola directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by