We have discussed why Node JS is single-threaded and also multi-threaded in our article called "Node Internals". It’ll give you a solid foundation on Node’s architecture and set the stage for understanding the magic of the Event Loop!
Node js could be considered single-threaded because of the Event Loop. But, what is the event loop?
I always start with the restaurant analogy because I think it becomes easy to understand technical details.
So, In the restaurant main chef takes orders from the order list and gives them to the team of assistants. When food is ready the chef serves the food. If any VIP customers come then the chef prioritize this order.
If we take this analogy into our consideration then we can say that...
In the context of Node JS Event Loop.
Chef is the Event Loop that manages tasks and delegating work.
Team of Assistance is a worker thread or the OS that handles the execution of the delegated tasks to them.
Order List is a task queue for tasks waiting for their turn.
VIP customer is a Microtask that has high priority and is completed before regular tasks.
To, Understand Event Loop we have to first understand the difference between Microtasks and Macrotasks.
Microtask
Microtask means tasks that have some high priority and are executed after the currently executing Javascript code completes, but before moving to the next phase of the Event Loop.
Example:
- process.nextTick
- Promises (.then, .catch, .finally)
- queueMicrotask
Macrotask
These are lower-priority tasks queued for execution at a later phase in the Event Loop.
Example:
- setTimeout
- setInterval
- setImmediate
- I/O operations
The Event Loop
When we run asynchronous tasks in Node.js, the Event Loop is at the heart of everything.
Thanks to the Event Loop, Node.js can perform non-blocking I/O operations efficiently. It achieves this by delegating time-consuming tasks to the operating system or worker threads. Once the tasks are completed, their callbacks are processed in an organized manner, ensuring smooth execution without blocking the main thread.
This is the magic that allows Node.js to handle multiple tasks concurrently while still being single-threaded.
Phases
There are six phases in an Event Loop and each phase has its own queue, which holds specific types of tasks.
1.Timers phase
In this phase timer related callbacks are handled such as setTimeout, and setInterval.
Node js checks the timer queue for callbacks whose delay has expired.
If a timer delay is met, its callback is added to this queue for execution.
console.log('Start'); setTimeout(() => { console.log('Timer 1 executed after 1 second'); }, 1000); setTimeout(() => { console.log('Timer 2 executed after 0.5 seconds'); }, 500); let count = 0; const intervalId = setInterval(() => { console.log('Interval callback executed'); count++; if (count === 3) { clearInterval(intervalId); console.log('Interval cleared'); } }, 1000); console.log('End');
Output:
Start End Timer 2 executed after 0.5 seconds Timer 1 executed after 1 second Interval callback executed Interval callback executed Interval callback executed Interval cleared
2.I/O callback phase
This phase's purpose is to execute callbacks for completed I/O (Input/Output) operations, such as reading or writing files, querying databases, handling network requests, and other asynchronous I/O tasks.
When you any asynchronous I/O operation in Node.js (like reading a file using fs.readFile) comes then, the operation is delegated to the operating system or worker threads. These I/O tasks are executed outside the main thread in a non-blocking manner. Once the task is completed, a callback function is triggered to process the results.
The I/O Callbacks Phase is where these callbacks are queued for execution once the operation finishes.
const fs = require('fs'); console.log('Start'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file:', err); return; } console.log('File contents:', data); }); console.log('Middle'); setTimeout(() => { console.log('Simulated network request completed'); }, 0); console.log('End');
Output
Start Middle End Simulated network request completed File contents: (contents of the example.txt file)
3.Idle phase
In this phase, no user-defined work is performed instead in this phase event loop gets ready for the next phases. only internal adjustments are done in this phase.
4.Poll phase
The Poll Phase checks whether there are pending I/O events (like network activity or file system events) that need to be processed. It will immediately execute the callbacks associated with these events.
If no I/O events are pending, the Poll Phase can enter a blocking state.
In this blocking state, Node.js will simply wait for new I/O events to arrive. This blocking state is what makes Node.js non-blocking: It waits until new I/O events trigger callback executions, keeping the main thread free for other tasks in the meantime.
Any callbacks for completed I/O operations (such as fs.readFile, HTTP requests, or database queries) are executed during this phase. These I/O operations may have been initiated in previous phases (like the Timers Phase or I/O Callbacks Phase) and are now completed.
If there are timers set with setTimeout or setInterval, Node.js will check if any timers have expired and if their associated callbacks need to be executed. If timers have expired, their callbacks are moved to the callback queue, but they will not be processed until the next phase, which is the Timers Phase.
const fs = require('fs'); const https = require('https'); console.log('Start'); fs.readFile('file1.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file1:', err); return; } console.log('File1 content:', data); }); fs.readFile('file2.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file2:', err); return; } console.log('File2 content:', data); }); https.get('https://jsonplaceholder.typicode.com/todos/1', (response) => { let data = ''; response.on('data', (chunk) => { data += chunk; }); response.on('end', () => { console.log('HTTP Response:', data); }); }); console.log('End');
Output:
Start End File1 content: (contents of file1.txt) File2 content: (contents of file2.txt) HTTP Response: (JSON data from the HTTP request)
5.Check phase
After the Poll Phase has completed its tasks. This phase mainly handles the execution of setImmediate callbacks, which are scheduled to run immediately after the I/O events are processed in the Poll Phase.
setImmediate callbacks are often used when you want to perform an action after the current event loop cycle, such as making sure some task is executed after the system is not busy processing I/O events.
The Check Phase has higher priority over the Timers Phase (which handles setTimeout and setInterval). This means that setImmediate callbacks will always be executed before any timers even if their timers have expired.
setImmediate guarantees that its callback will run after the current I/O cycle and before the next timer cycle. This can be important when you want to ensure that I/O-related tasks are completed first before running other tasks.
console.log('Start'); setTimeout(() => { console.log('Timer 1 executed after 1 second'); }, 1000); setTimeout(() => { console.log('Timer 2 executed after 0.5 seconds'); }, 500); let count = 0; const intervalId = setInterval(() => { console.log('Interval callback executed'); count++; if (count === 3) { clearInterval(intervalId); console.log('Interval cleared'); } }, 1000); console.log('End');
Output:
Start End Timer 2 executed after 0.5 seconds Timer 1 executed after 1 second Interval callback executed Interval callback executed Interval callback executed Interval cleared
6.close phase
The Close Callbacks Phase typically executes when an application needs to clean up before exiting or shutting down.
This phase deals with events and tasks that need to be executed once a system resource, like a network socket or file handle, is no longer needed.
Without this phase, an application might leave open file handles, network connections, or other resources, potentially leading to memory leaks, data corruption, or other issues.
const fs = require('fs'); console.log('Start'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file:', err); return; } console.log('File contents:', data); }); console.log('Middle'); setTimeout(() => { console.log('Simulated network request completed'); }, 0); console.log('End');
Output:
Start Middle End Simulated network request completed File contents: (contents of the example.txt file)
There is one more special phase in the Event Loop of Node JS.
Microtask Queue
process.nextTick() and promises to execute their callbacks in a special phase in the Event Loop.
process.nextTick() schedules a callback to be executed immediately after the current operation completes, but before the event loop continues to the next phase.
process.nextTick() is not part of any phase in the event loop. Instead, it has its own internal queue that gets executed right after the currently executing synchronous code and before any phase in the event loop is entered.
It's executed after the current operation but before I/O, setTimeout, or other tasks scheduled in the event loop.
Promises have lower priority than process.nextTick() and are processed after all process.nextTick() callbacks.
const fs = require('fs'); const https = require('https'); console.log('Start'); fs.readFile('file1.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file1:', err); return; } console.log('File1 content:', data); }); fs.readFile('file2.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file2:', err); return; } console.log('File2 content:', data); }); https.get('https://jsonplaceholder.typicode.com/todos/1', (response) => { let data = ''; response.on('data', (chunk) => { data += chunk; }); response.on('end', () => { console.log('HTTP Response:', data); }); }); console.log('End');
Output:
Start End File1 content: (contents of file1.txt) File2 content: (contents of file2.txt) HTTP Response: (JSON data from the HTTP request)
Now, You have an overall idea of how the Event Loop works.
I am giving you one question which answer you can give in the comments.
const fs = require('fs'); console.log('Start'); fs.readFile('somefile.txt', 'utf8', (err, data) => { if (err) { console.error(err); return; } console.log('File content:', data); }); setImmediate(() => { console.log('Immediate callback executed'); }); setTimeout(() => { console.log('Timeout callback executed'); }, 0); console.log('End');
Thank you.
Waiting for your answer.
The above is the detailed content of Node JS - The Event Loop. For more information, please follow other related articles on the PHP Chinese website!

Yes, the engine core of JavaScript is written in C. 1) The C language provides efficient performance and underlying control, which is suitable for the development of JavaScript engine. 2) Taking the V8 engine as an example, its core is written in C, combining the efficiency and object-oriented characteristics of C. 3) The working principle of the JavaScript engine includes parsing, compiling and execution, and the C language plays a key role in these processes.

JavaScript is at the heart of modern websites because it enhances the interactivity and dynamicity of web pages. 1) It allows to change content without refreshing the page, 2) manipulate web pages through DOMAPI, 3) support complex interactive effects such as animation and drag-and-drop, 4) optimize performance and best practices to improve user experience.

C and JavaScript achieve interoperability through WebAssembly. 1) C code is compiled into WebAssembly module and introduced into JavaScript environment to enhance computing power. 2) In game development, C handles physics engines and graphics rendering, and JavaScript is responsible for game logic and user interface.

JavaScript is widely used in websites, mobile applications, desktop applications and server-side programming. 1) In website development, JavaScript operates DOM together with HTML and CSS to achieve dynamic effects and supports frameworks such as jQuery and React. 2) Through ReactNative and Ionic, JavaScript is used to develop cross-platform mobile applications. 3) The Electron framework enables JavaScript to build desktop applications. 4) Node.js allows JavaScript to run on the server side and supports high concurrent requests.

Python is more suitable for data science and automation, while JavaScript is more suitable for front-end and full-stack development. 1. Python performs well in data science and machine learning, using libraries such as NumPy and Pandas for data processing and modeling. 2. Python is concise and efficient in automation and scripting. 3. JavaScript is indispensable in front-end development and is used to build dynamic web pages and single-page applications. 4. JavaScript plays a role in back-end development through Node.js and supports full-stack development.

C and C play a vital role in the JavaScript engine, mainly used to implement interpreters and JIT compilers. 1) C is used to parse JavaScript source code and generate an abstract syntax tree. 2) C is responsible for generating and executing bytecode. 3) C implements the JIT compiler, optimizes and compiles hot-spot code at runtime, and significantly improves the execution efficiency of JavaScript.

JavaScript's application in the real world includes front-end and back-end development. 1) Display front-end applications by building a TODO list application, involving DOM operations and event processing. 2) Build RESTfulAPI through Node.js and Express to demonstrate back-end applications.

The main uses of JavaScript in web development include client interaction, form verification and asynchronous communication. 1) Dynamic content update and user interaction through DOM operations; 2) Client verification is carried out before the user submits data to improve the user experience; 3) Refreshless communication with the server is achieved through AJAX technology.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

DVWA
Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

EditPlus Chinese cracked version
Small size, syntax highlighting, does not support code prompt function

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool

SublimeText3 Linux new version
SublimeText3 Linux latest version
