Node.js uses a single-threaded event loop to handle asynchronous operations. This means that all the JavaScript code is executed on a single thread, but the event loop can handle multiple operations concurrently.
The JavaScript code consists of two lines of execution:
- The mainline: This is the JavaScript that runs when Node first runs your program. It runs from start to finish, and when it is finished, it gives up control to the event loop.
- The event loop: This is where all of your callbacks are run.
The following diagram shows a simplified overview of the event loop's order of operations.
┌───────────────────────────┐
┌─>│ timers │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
│ └─────────────┬─────────────┘ ┌───────────────┐
│ ┌─────────────┴─────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └─────────────┬─────────────┘ │ data, etc. │
│ ┌─────────────┴─────────────┐ └───────────────┘
│ │ check │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ close callbacks │
└───────────────────────────┘
The event loop in Node.js does not have a predefined number of iterations; it continues running indefinitely until there are no more tasks to perform. Each iteration of the event loop is referred to as a tick. The event loop will keep ticking as long as there are pending operations, such as:
- Promises and other microtasks.
- Pending timers (callbacks scheduled with
setTimeout
orsetInterval
). - Pending I/O operations (e.g., file system operations, network requests).
- Pending callbacks (e.g., deferred I/O callbacks).
setImmediate
callbacks.- Close callbacks.
Microtasks
All microtasks are placed into a microtask queue, designed specifically for handling them.
The microtask queue is processed and emptied before every phase iteration of the event loop.
Microtasks are executed at specific points in the event loop:
- After executing JavaScript code: When the call stack becomes empty, the event loop checks for and executes any pending microtasks before moving to the next phase.
- After processing each phase of the event loop: Once the current phase of the event loop is completed, before moving to the next phase, the event loop processes all the pending microtasks.
Here are the main types of microtasks:
- Promise Callbacks:
.then()
,.catch()
, and.finally()
handlers. queueMicrotask
: Both queueMicrotask and Promise Callbacks added to the microtask queue and have similar priority.process.nextTick
: Callbacks scheduled withprocess.nextTick
are executed before promise callbacks or queueMicrotask callbacks.process.nextTick
callbacks are added to the beginning of the microtask queue.
Here's an example:
console.log('Start');
process.nextTick(console.log, "nextTick 1");
Promise.resolve("Promise 1").then(console.log);
queueMicrotask(() => console.log("queueMicrotask 1"));
Promise.reject("Promise 2").catch(console.log);
queueMicrotask(() => console.log("queueMicrotask 2"));
process.nextTick(console.log, "nextTick 2");
console.log('End');
The output would be:
Start
End
nextTick 1
nextTick 2
Promise 1
queueMicrotask 1
Promise 2
queueMicrotask 2
The execution flow is as follows:
- The mainline
- The main thread starts by creating the global execution context and pushes it onto the call stack.
- The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"Start"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread executes
process.nextTick
function call, a function execution context forprocess.nextTick
is added to the call stack. - The main thread moves the
process.nextTick
callback function to the next tick queue. - The main thread removes the function execution context for
process.nextTick
from the call stack. - The main thread executes Promise constructor call, and its execution context is created and pushed onto the call stack.
- The executor function within the Promise constructor initializes the promise.
- The main thread executes executor function call, and its execution context is created and pushed onto the call stack.
- The main thread executes resolve function call, and its execution context is created and pushed onto the call stack.
- Calling resolve transitions the promise from the pending state to the fulfilled (or resolved) state.
- The value "Promise 1" is set as the value of the new promise internally.
- The main thread removes function execution context for
resolve
from the call stack. - The main thread removes function execution context for
executor function
from the call stack. - The Promise constructor completes, and its execution context is popped off the call stack.
- The main thread executes
.then()
method call, and its execution context is created and pushed onto the call stack. - The main thread moves the resolve callback function to the microtask queue (or job queue).
- The main thread removes the execution context for
then()
from the call stack. - The main thread executes
queueMicrotask
function call, a function execution context forqueueMicrotask
is added to the call stack. - The main thread moves the
queueMicrotask
callback function to the microtask queue. - The main thread removes the function execution context for
queueMicrotask
from the call stack. - The main thread executes the second Promise constructor call, and its execution context is created and pushed onto the call stack.
- The executor function within the second Promise constructor initializes the promise.
- The main thread executes executor function call, and its execution context is created and pushed onto the call stack.
- The main thread executes reject function call, and its execution context is created and pushed onto the call stack.
- Calling resolve transitions the promise from the pending state to the rejected state.
- The value "Promise 2" is set as the value of the new promise internally.
- The main thread removes function execution context for
reject
from the call stack. - The main thread removes function execution context for
executor function
from the call stack. - The second Promise constructor completes, and its execution context is popped off the call stack.
- The main thread executes
.then()
method call, and its execution context is created and pushed onto the call stack. - The main thread moves the resolve callback function to the microtask queue (or job queue).
- The main thread removes the execution context for
then()
from the call stack. - The main thread executes the second
queueMicrotask
function call, a function execution context for the secondqueueMicrotask
is added to the call stack. - The main thread moves the second
queueMicrotask
callback function to the microtask queue. - The main thread removes the function execution context for the second
queueMicrotask
from the call stack. - The main thread executes the second
process.nextTick
function call, a function execution context for the secondprocess.nextTick
is added to the call stack. - The main thread moves the second
process.nextTick
callback function to the next tick queue. - The main thread removes the function execution context for the second
process.nextTick
from the call stack. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"End"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - Once all the synchronous code has executed, the main thread removes the global execution context from the call stack.
- The call stack is now empty, waiting for asynchronous callbacks to be executed.
- The event loop starts processing the asynchronous callbacks that have been registered.
- The first loop
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for the first
process.nextTick
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"nextTick 1"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread removes the function execution context for the first
process.nextTick
callback function from the call stack. - The event loop pushes the second task from the nextTick queue onto the call stack and creates a new function execution context for the second
process.nextTick
callback function. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"nextTick 2"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread removes the function execution context for the second
process.nextTick
callback function from the call stack. - The event loop pushes the task from the microtask queue onto the call stack and creates a new function execution context for promise
then()
callback function. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"Promise 1"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread removes the function execution context for promise
then()
callback function from the call stack. - The event loop pushes the next task from the microtask queue onto the call stack and creates a new function execution context for
queueMicrotask
callback function. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"queueMicrotask 1"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread removes the function execution context for
queueMicrotask
callback function from the call stack. - The event loop pushes the next task from the microtask queue onto the call stack and creates a new function execution context for promise
then()
callback function. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"Promise 2"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread removes the function execution context for promise
then()
callback function from the call stack. - The event loop pushes the next task from the microtask queue onto the call stack and creates a new function execution context for the second
queueMicrotask
callback function. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"queueMicrotask 2"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread removes the function execution context for the second
queueMicrotask
callback function from the call stack.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for the first
- Timers Phase
- No timers have expired yet (since less than 500 milliseconds have passed).
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Pending Callbacks Phase
- No pending callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- No I/O events to process.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
Timers
The first phase of the event loop is the Timers phase. This phase deals with timer callbacks that have reached their scheduled time. Timers in Node.js can be used to schedule code execution after a specified delay or at specific intervals. When a timer's time comes, its callback function is added to the event queue (task queue) to be executed.
Timers are not guaranteed to execute exactly at their scheduled time, as they are subject to the availability of the system and the event loop. For example, if the event loop is busy processing other events, the timer callback may be delayed until the next iteration of the event loop. Therefore, timers should not be used for precise timing, but rather for approximate timing.
Here's an example:
console.log('Start');
setTimeout(() => {
console.log('Timeout callback 1');
}, 1000);
setTimeout(() => {
console.log('Timeout callback 2');
}, 500);
process.nextTick(console.log, "nextTick callback");
queueMicrotask(() => console.log("queueMicrotask callback"));
console.log('End');
The output would be:
Start
End
nextTick callback
queueMicrotask callback
Timeout callback 2
Timeout callback 1
The execution flow is as follows:
- The mainline
- The main thread starts by creating the global execution context and pushes it onto the call stack.
- The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"Start"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread executes
setTimeout
function call, a function execution context forsetTimeout
is added to the call stack. - The main thread adds the
setTimeout
callback function to the timer queue. - The event loop continuously checks the timer queue. When the specified delay has elapsed, the callback function is moved to the appropriate phase of the event loop.
- The main thread removes the function execution context for
setTimeout
from the call stack. - The main thread executes the second
setTimeout
function call, a function execution context for the secondsetTimeout
is added to the call stack. - The main thread adds the second
setTimeout
callback function to the timer queue. - The event loop continuously checks the timer queue. When the specified delay has elapsed, the callback function is moved to the appropriate phase of the event loop.
- The main thread removes the function execution context for the second
setTimeout
from the call stack. - The main thread executes
process.nextTick
function call, a function execution context forprocess.nextTick
is added to the call stack. - The main thread moves the
process.nextTick
callback function to the next tick queue. - The main thread removes the function execution context for
process.nextTick
from the call stack. - The main thread executes
queueMicrotask
function call, a function execution context forqueueMicrotask
is added to the call stack. - The main thread moves the
queueMicrotask
callback function to the microtask queue. - The main thread removes the function execution context for
queueMicrotask
from the call stack. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"End"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - Once all the synchronous code has executed, the main thread removes the global execution context from the call stack.
- The call stack is now empty, waiting for asynchronous callbacks to be executed.
- The event loop starts processing the asynchronous callbacks that have been registered.
- The first loop
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for
process.nextTick
callback function. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"nextTick callback"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread removes the function execution context for
process.nextTick
callback function from the call stack. - The event loop pushes the task from the microtask queue onto the call stack and creates a new function execution context for
queueMicrotask
callback function. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"queueMicrotask callback"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread removes the function execution context for
queueMicrotask
callback function from the call stack.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for
- Timers Phase
- No timers have expired yet (since less than 500 milliseconds have passed).
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Pending Callbacks Phase
- No pending callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- No I/O events to process.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop will continue to loop.
- The next loop
- The first loop starts by running the microtasks queue.
- No microtasks to execute.
- Timers Phase (After 500 milliseconds)
- The event loop pushes the task from the callback queue onto the call stack and creates a new function execution context for the second
setTimeout
callback function. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"Timeout callback 2"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread removes the function execution context for
setTimeout
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the callback queue onto the call stack and creates a new function execution context for the second
- Pending Callbacks Phase
- No pending callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- No I/O events to process.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue.
- The event loop will continue to loop.
- The next loop
- The first loop starts by running the microtasks queue.
- No microtasks to execute.
- Timers Phase (After 1000 milliseconds)
- The event loop pushes the task from the callback queue onto the call stack and creates a new function execution context for the first
setTimeout
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Timeout callback 1"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The event loop removes the function execution context for
setTimeout
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the callback queue onto the call stack and creates a new function execution context for the first
- Pending Callbacks Phase
- No pending callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- No I/O events to process.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue.
Pending Callbacks
I/O operations execute in the poll phase of the event loop. During the poll phase, some specific I/O operations callbacks defer to the pending phase of the next iteration of the event loop. I/O operations callbacks deferred from the previous iteration run in the pending callbacks phase.
Here's an example:
console.log('Start');
const fs = require("fs");
fs.readFile(__filename, (err, data) => {
if (err) throw err;
console.log("Pending callback");
});
setTimeout(() => {
console.log('Timeout callback');
}, 0);
process.nextTick(console.log, "nextTick callback");
queueMicrotask(() => console.log("queueMicrotask callback"));
console.log('End');
The output would be:
Start
End
nextTick callback
queueMicrotask callback
Timeout callback
Pending callback
The execution flow is as follows:
- The mainline
- The main thread starts by creating the global execution context and pushes it onto the call stack.
- The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"Start"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread executes
require
function call, a function execution context forrequire
is added to the call stack. - The main thread starts resolving the module identifier
fs
. - The main thread wraps the contents of
fs
in a function and executes it, a function execution context forfs
is added to the call stack. - The
module.exports
object is returned and assigned tofs
. - The main thread removes function execution context for
fs
from the call stack. - The main thread removes function execution context for
require
from the call stack. - The main thread executes
fs.readFile
function call, a function execution context forfs.readFile
is added to the call stack. - The main thread initiates a non-blocking file system operation to read the current file.
- The main thread removes the function execution context for the first
fs.readFile
from the call stack. - The main thread executes
setTimeout
function call, a function execution context forsetTimeout
is added to the call stack. - The main thread adds the
setTimeout
callback function to the timer queue. - The event loop continuously checks the timer queue. When the specified delay has elapsed, the callback function is moved to the appropriate phase of the event loop.
- The main thread removes the function execution context for
setTimeout
from the call stack. - The main thread executes
process.nextTick
function call, a function execution context forprocess.nextTick
is added to the call stack. - The main thread moves the
process.nextTick
callback function to the next tick queue. - The main thread removes the function execution context for
process.nextTick
from the call stack. - The main thread executes
queueMicrotask
function call, a function execution context forqueueMicrotask
is added to the call stack. - The main thread moves the
queueMicrotask
callback function to the microtask queue. - The main thread removes the function execution context for
queueMicrotask
from the call stack. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"End"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - Once all the synchronous code has executed, the main thread removes the global execution context from the call stack.
- The call stack is now empty, waiting for asynchronous callbacks to be executed.
- The event loop starts processing the asynchronous callbacks that have been registered.
- The first loop
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for
process.nextTick
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"nextTick callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The event loop removes the function execution context for
process.nextTick
callback function from the call stack. - The event loop pushes the task from the microtask queue onto the call stack and creates a new function execution context for
queueMicrotask
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"queueMicrotask callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The event loop removes the function execution context for
queueMicrotask
callback function from the call stack.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for
- Timers Phase
- The event loop pushes the task from the timer queue onto the call stack and creates a new function execution context for
setTimeout
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Timeout callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The event loop removes the function execution context for
setTimeout
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the timer queue onto the call stack and creates a new function execution context for
- Pending Callbacks Phase
- The file reading process is finished, but its callback is not yet marked to be executed because IO callbacks get queued up only at the IO Poll Phase.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- The
fs.readFile
callback event is collected and added to the I/O queue. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop will continue to loop.
- The next loop
- The first loop starts by running the microtasks queue.
- No microtasks to execute.
- Timers Phase
- No timeout callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Pending Callbacks Phase
- The event loop pushes the task from the I/O queue onto the call stack and creates a new function execution context for
fs.readFile
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Pending callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The event loop removes the function execution context for
fs.readFile
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the I/O queue onto the call stack and creates a new function execution context for
- Poll Phase
- No I/O events to process.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue.
Idle Phase
The idle phase is not a normal phase of the Node.js event loop. It is a period whereby the event loop has nothing to do but perform background tasks like checking for low-priority results or running garbage collection.
Poll Phase
The poll phase is where I/O operations execute. I/O operations transfer data to or from a computer. The event loop checks for new I/O operations and executes them in the poll queue.
Here's an example:
console.log('Start');
const fs = require("fs");
fs.readFile(__filename, (err, data) => {
if (err) throw err;
console.log("Pending callback");
});
const http = require("http");
http.get("http://localhost", (res) => {
console.log("Poll callback");
res.on("data", (chunk) => {
// Do something with the data
console.log("Data event listener callback");
});
});
setTimeout(() => {
console.log('Timeout callback');
}, 0);
process.nextTick(console.log, "nextTick callback");
queueMicrotask(() => console.log("queueMicrotask callback"));
console.log('End');
The output would be:
Start
End
nextTick callback
queueMicrotask callback
Timeout callback
Poll callback
Data event listener callback
Pending callback
The execution flow is as follows:
- The mainline
- The main thread starts by creating the global execution context and pushes it onto the call stack.
- The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"Start"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread executes
require
function call, a function execution context forrequire
is added to the call stack. - The main thread starts resolving the module identifier
fs
. - The main thread wraps the contents of
fs
in a function and executes it, a function execution context forfs
is added to the call stack. - The
module.exports
object is returned and assigned tofs
. - The main thread removes function execution context for
fs
from the call stack. - The main thread removes function execution context for
require
from the call stack. - The main thread executes
fs.readFile
function call, a function execution context forfs.readFile
is added to the call stack. - The main thread initiates a non-blocking file system operation to read the current file.
- The main thread moves the
fs.readFile
callback function to the I/O queue. - The main thread removes the function execution context for the first
fs.readFile
from the call stack. - The main thread executes
require
function call, a function execution context forrequire
is added to the call stack. - The main thread starts resolving the module identifier
http
. - The main thread wraps the contents of
http
in a function and executes it, a function execution context forhttp
is added to the call stack. - The
module.exports
object is returned and assigned tohttp
. - The main thread removes function execution context for
http
from the call stack. - The main thread removes function execution context for
require
from the call stack. - The main thread executes
http.get
function call, a function execution context forhttp.get
is added to the call stack. - The main thread initiates initiates an HTTP GET request.
- The main thread moves the
http.get
callback function to the I/O queue. - The main thread removes the function execution context for the first
http.get
from the call stack. - The main thread executes
setTimeout
function call, a function execution context forsetTimeout
is added to the call stack. - The main thread adds the
setTimeout
callback function to the timer queue. - The event loop continuously checks the timer queue. When the specified delay has elapsed, the callback function is moved to the appropriate phase of the event loop.
- The main thread removes the function execution context for
setTimeout
from the call stack. - The main thread executes
process.nextTick
function call, a function execution context forprocess.nextTick
is added to the call stack. - The main thread moves the
process.nextTick
callback function to the next tick queue. - The main thread removes the function execution context for
process.nextTick
from the call stack. - The main thread executes
queueMicrotask
function call, a function execution context forqueueMicrotask
is added to the call stack. - The main thread moves the
queueMicrotask
callback function to the microtask queue. - The main thread removes the function execution context for
queueMicrotask
from the call stack. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"End"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - Once all the synchronous code has executed, the main thread removes the global execution context from the call stack.
- The call stack is now empty, waiting for asynchronous callbacks to be executed.
- The event loop starts processing the asynchronous callbacks that have been registered.
- The first loop
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for
process.nextTick
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"nextTick callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The event loop removes the function execution context for
process.nextTick
callback function from the call stack. - The event loop pushes the task from the microtask queue onto the call stack and creates a new function execution context for
queueMicrotask
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"queueMicrotask callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes the function execution context for
queueMicrotask
callback function from the call stack.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for
- Timers Phase
- The event loop pushes the task from the timer queue onto the call stack and creates a new function execution context for
setTimeout
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Timeout callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes the function execution context for
setTimeout
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the timer queue onto the call stack and creates a new function execution context for
- Pending Callbacks Phase
- No pending callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- The file reading process isn't finished.
- The HTTP request is sent over the network and waits for the server response.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop will continue to loop.
- The next loop
- The first loop starts by running the microtasks queue.
- No microtasks to execute.
- Timers Phase
- No timeout callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Pending Callbacks Phase
- The file reading process is finished, but its callback is not yet marked to be executed because IO callbacks get queued up only at the IO Poll Phase.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- The
fs.readFile
callback event is collected and added to the I/O queue. - When the response headers from the server are received, the event loop pushes the task from the I/O queue onto the call stack and creates a new function execution context for
http.get
callback function. - The server
localhost
responds HTTP GET request, the data starts arriving in chunks. - The event loop executes the data event listener call, a function execution context for data event listener is added to the call stack.
- The event loop moves the calbback function for data event listener to the event queue (task queue).
- Each chunk of data triggers a data event on the response object.
- Once the event loop detects the data event, the event loop will move the callback function for data event listener from the event queue (task queue) to the call stack to be executed and create a new function execution context for callback function.
- The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Data event listener callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes function execution context for callback function from the call stack.
- The data event listener also has no more code to run.
- The event loop removes function execution context for data event listener from the call stack.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue.
- The event loop will continue to loop.
- The next loop
- The first loop starts by running the microtasks queue.
- No microtasks to execute.
- Timers Phase
- No timeout callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Pending Callbacks Phase
- The event loop pushes the task from the I/O queue onto the call stack and creates a new function execution context for
fs.readFile
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Pending callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes the function execution context for
fs.readFile
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the I/O queue onto the call stack and creates a new function execution context for
- Poll Phase
- No I/O events to process.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue.
Check Phase
The check phase is where the setImmediate
timer runs. The Node.js event loop goes to the check phase when there is a setImmediate
in the program, and the poll phase becomes idle or when the poll phase completes.
Here's an example:
console.log('Start');
const fs = require("fs");
fs.readFile(__filename, (err, data) => {
if (err) throw err;
console.log("Pending callback");
});
const http = require("http");
http.get("http://localhost", (res) => {
console.log("Poll callback");
res.on("data", (chunk) => {
// Do something with the data
console.log("Data event listener callback");
});
});
setTimeout(() => {
console.log('Timeout callback');
}, 0);
setImmediate(() => {
console.log("Check callback");
});
process.nextTick(console.log, "nextTick callback");
queueMicrotask(() => console.log("queueMicrotask callback"));
console.log('End');
The output would be:
Start
End
nextTick callback
queueMicrotask callback
Timeout callback
Check callback
Poll callback
Data event listener callback
Pending callback
The execution flow is as follows:
- The mainline
- The main thread starts by creating the global execution context and pushes it onto the call stack.
- The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"Start"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread executes
require
function call, a function execution context forrequire
is added to the call stack. - The main thread starts resolving the module identifier
fs
. - The main thread wraps the contents of
fs
in a function and executes it, a function execution context forfs
is added to the call stack. - The
module.exports
object is returned and assigned tofs
. - The main thread removes function execution context for
fs
from the call stack. - The main thread removes function execution context for
require
from the call stack. - The main thread executes
fs.readFile
function call, a function execution context forfs.readFile
is added to the call stack. - The main thread initiates a non-blocking file system operation to read the current file.
- The main thread moves the
fs.readFile
callback function to the I/O queue. - The main thread removes the function execution context for the first
fs.readFile
from the call stack. - The main thread executes
require
function call, a function execution context forrequire
is added to the call stack. - The main thread starts resolving the module identifier
http
. - The main thread wraps the contents of
http
in a function and executes it, a function execution context forhttp
is added to the call stack. - The
module.exports
object is returned and assigned tohttp
. - The main thread removes function execution context for
http
from the call stack. - The main thread removes function execution context for
require
from the call stack. - The main thread executes
http.get
function call, a function execution context forhttp.get
is added to the call stack. - The main thread initiates initiates an HTTP GET request.
- The main thread moves the
http.get
callback function to the I/O queue. - The main thread removes the function execution context for the first
http.get
from the call stack. - The main thread executes
setTimeout
function call, a function execution context forsetTimeout
is added to the call stack. - The main thread adds the
setTimeout
callback function to the timer queue. - The event loop continuously checks the timer queue. When the specified delay has elapsed, the callback function is moved to the appropriate phase of the event loop.
- The main thread removes the function execution context for
setTimeout
from the call stack. - The main thread executes
setImmediate
function call, a function execution context forconsole.log
is added to the call stack. - The main thread moves the
setImmediate
callback function to the check queue. - The main thread removes function execution context for
setImmediate
from the call stack. - The main thread executes
process.nextTick
function call, a function execution context forprocess.nextTick
is added to the call stack. - The main thread moves the
process.nextTick
callback function to the next tick queue. - The main thread removes the function execution context for
process.nextTick
from the call stack. - The main thread executes
queueMicrotask
function call, a function execution context forqueueMicrotask
is added to the call stack. - The main thread moves the
queueMicrotask
callback function to the microtask queue. - The main thread removes the function execution context for
queueMicrotask
from the call stack. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"End"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - Once all the synchronous code has executed, the main thread removes the global execution context from the call stack.
- The call stack is now empty, waiting for asynchronous callbacks to be executed.
- The event loop starts processing the asynchronous callbacks that have been registered.
- The first loop
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for
process.nextTick
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"nextTick callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The event loop removes the function execution context for
process.nextTick
callback function from the call stack. - The event loop pushes the task from the microtask queue onto the call stack and creates a new function execution context for
queueMicrotask
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"queueMicrotask callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes the function execution context for
queueMicrotask
callback function from the call stack.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for
- Timers Phase
- The event loop pushes the task from the timer queue onto the call stack and creates a new function execution context for
setTimeout
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Timeout callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes the function execution context for
setTimeout
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the timer queue onto the call stack and creates a new function execution context for
- Pending Callbacks Phase
- No pending callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- The file reading operation isn't finished.
- The HTTP request is sent over the network and waits for the server response.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- The event loop pushes the task from the check queue onto the call stack and creates a new function execution context for
setImmediate
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Check callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes the function execution context for
setImmediate
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the check queue onto the call stack and creates a new function execution context for
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop will continue to loop.
- The next loop
- The first loop starts by running the microtasks queue.
- No microtasks to execute.
- Timers Phase
- No timeout callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Pending Callbacks Phase
- The file reading operation is finished, but its callback is not yet marked to be executed because IO callbacks get queued up only at the IO Poll Phase.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- The
fs.readFile
callback event is collected and added to the I/O queue. - When the response headers from the server are received, the event loop pushes the task from the I/O queue onto the call stack and creates a new function execution context for
http.get
callback function. - The server
localhost
responds HTTP GET request, the data starts arriving in chunks. - The event loop executes the data event listener call, a function execution context for data event listener is added to the call stack.
- The event loop moves the calbback function for data event listener to the event queue (task queue).
- Each chunk of data triggers a data event on the response object.
- Once the event loop detects the data event, the event loop will move the callback function for data event listener from the event queue (task queue) to the call stack to be executed and create a new function execution context for callback function.
- The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Data event listener callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes function execution context for callback function from the call stack.
- The data event listener also has no more code to run.
- The event loop removes function execution context for data event listener from the call stack.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue.
- The event loop will continue to loop.
- The next loop
- The first loop starts by running the microtasks queue.
- No microtasks to execute.
- Timers Phase
- No timeout callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Pending Callbacks Phase
- The event loop pushes the task from the I/O queue onto the call stack and creates a new function execution context for
fs.readFile
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Pending callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes the function execution context for
fs.readFile
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the I/O queue onto the call stack and creates a new function execution context for
- Poll Phase
- No I/O events to process.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue.
Close Callbacks Phase
The close callbacks phase is the last phase of the Node.js event loop. The close callback phase is where callbacks from the close event of a socket and the closing of an HTTP server run.
The close callbacks phase is designed to handle cleanup operations related to resource closure, such as the closing of TCP connections, file descriptors, and other resources.
Here's an example:
console.log('Start');
const fs = require('fs');
const readable = fs.createReadStream(__filename);
readable.on('data', (chunk) => {
console.log('Data event listener');
});
readable.on('close', () => {
console.log('Close callback');
});
const http = require("http");
http.get("http://localhost", (res) => {
console.log("Poll callback");
res.on("data", (chunk) => {
// Do something with the data
console.log("Data event listener callback");
});
});
setTimeout(() => {
console.log('Timeout callback');
}, 0);
setImmediate(() => {
console.log("Check callback");
});
process.nextTick(console.log, "nextTick callback");
queueMicrotask(() => console.log("queueMicrotask callback"));
console.log('End');
The output depends on which operation finishes first, the HTTP request or the file reading operation.
The output would be:
Start
End
nextTick callback
queueMicrotask callback
Timeout callback
Check callback
Poll callback
Data event listener callback
Pending callback
Or:
Start
End
nextTick callback
queueMicrotask callback
Timeout callback
Check callback
Data event listener
Poll callback
Data event listener callback
Close callback
The execution flow is as follows:
- The mainline
- The main thread starts by creating the global execution context and pushes it onto the call stack.
- The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"Start"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - The main thread executes
require
function call, a function execution context forrequire
is added to the call stack. - The main thread starts resolving the module identifier
fs
. - The main thread wraps the contents of
fs
in a function and executes it, a function execution context forfs
is added to the call stack. - The
module.exports
object is returned and assigned toreadable
. - The main thread removes function execution context for
fs
from the call stack. - The main thread removes function execution context for
require
from the call stack. - The main thread executes
fs.createReadStream
function call, a function execution context forfs.createReadStream
is added to the call stack. - The main thread initiates a non-blocking file system operation to read the current file.
- This function is synchronous, meaning it runs immediately and returns a Readable stream object assigned to the
readable
. - The main thread moves the
fs.createReadStream
callback function to the I/O queue. - The main thread removes the function execution context for the first
fs.createReadStream
from the call stack. - The main thread executes
readable.on
function call, a function execution context forreadable.on
is added to the call stack. - The main thread moves the callback function to the event queue (task queue) which will be invoked whenever a chunk of data is available to be read from the stream.
- This callback is an asynchronous event listener, meaning it will be called asynchronously whenever the 'data' event is emitted.
- The main thread moves the
readable.on
callback function to the I/O queue. - The main thread executes the second
readable.on
function call, a function execution context forreadable.on
is added to the call stack. - The main thread moves the callback function to the event queue (task queue) which will be invoked when the stream is closed.
- This callback is also asynchronous and will be called when the 'close' event is emitted.
- The main thread moves the
readable.on
callback function to the I/O queue. - The main thread executes
require
function call, a function execution context forrequire
is added to the call stack. - The main thread starts resolving the module identifier
http
. - The main thread wraps the contents of
http
in a function and executes it, a function execution context forhttp
is added to the call stack. - The
module.exports
object is returned and assigned tohttp
. - The main thread removes function execution context for
http
from the call stack. - The main thread removes function execution context for
require
from the call stack. - The main thread executes
http.get
function call, a function execution context forhttp.get
is added to the call stack. - The main thread initiates initiates an HTTP GET request.
- The main thread moves the
http.get
callback function to the I/O queue. - The main thread removes the function execution context for the first
http.get
from the call stack. - The main thread executes
setTimeout
function call, a function execution context forsetTimeout
is added to the call stack. - The main thread adds the
setTimeout
callback function to the timer queue. - The event loop continuously checks the timer queue. When the specified delay has elapsed, the callback function is moved to the appropriate phase of the event loop.
- The main thread removes the function execution context for
setTimeout
from the call stack. - The main thread executes
setImmediate
function call, a function execution context forconsole.log
is added to the call stack. - The main thread moves the
setImmediate
callback function to the check queue. - The main thread removes function execution context for
setImmediate
from the call stack. - The main thread executes
process.nextTick
function call, a function execution context forprocess.nextTick
is added to the call stack. - The main thread moves the
process.nextTick
callback function to the next tick queue. - The main thread removes the function execution context for
process.nextTick
from the call stack. - The main thread executes
queueMicrotask
function call, a function execution context forqueueMicrotask
is added to the call stack. - The main thread moves the
queueMicrotask
callback function to the microtask queue. - The main thread removes the function execution context for
queueMicrotask
from the call stack. - The main thread executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The main thread logs
"End"
to the console. - The main thread removes function execution context for
console.log
from the call stack. - Once all the synchronous code has executed, the main thread removes the global execution context from the call stack.
- The call stack is now empty, waiting for asynchronous callbacks to be executed.
- The event loop starts processing the asynchronous callbacks that have been registered.
- The first loop
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for
process.nextTick
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"nextTick callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The event loop removes the function execution context for
process.nextTick
callback function from the call stack. - The event loop pushes the task from the microtask queue onto the call stack and creates a new function execution context for
queueMicrotask
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"queueMicrotask callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes the function execution context for
queueMicrotask
callback function from the call stack.
- The event loop pushes the task from the nextTick queue onto the call stack and creates a new function execution context for
- Timers Phase
- The event loop pushes the task from the timer queue onto the call stack and creates a new function execution context for
setTimeout
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Timeout callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes the function execution context for
setTimeout
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the timer queue onto the call stack and creates a new function execution context for
- Pending Callbacks Phase
- No pending callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- The event loop waits for data from streams.
- The HTTP request is sent over the network and waits for the server response.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- The event loop pushes the task from the check queue onto the call stack and creates a new function execution context for
setImmediate
callback function. - The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Check callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes the function execution context for
setImmediate
callback function from the call stack. - The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The event loop pushes the task from the check queue onto the call stack and creates a new function execution context for
- Close Callbacks Phase
- No close callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue. The nextTick queue gets priority over the microtask queue.
- The event loop will continue to loop.
- The next loop
- The first loop starts by running the microtasks queue.
- No microtasks to execute.
- Timers Phase
- No timeout callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Pending Callbacks Phase
- No pending callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Poll Phase
- When a chunk of data is received, the event loop will move the callback function for data event listener from the event queue (task queue) to the call stack to be executed and create a new function execution context for callback function.
- Each chunk of data triggers a data event on the readable stream object.
- The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Data event listener"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes function execution context for callback function from the call stack.
- When the response headers from the server are received, the event loop pushes the task from the I/O queue onto the call stack and creates a new function execution context for
http.get
callback function. - The server
localhost
responds HTTP GET request, the data starts arriving in chunks. - The event loop executes the data event listener call, a function execution context for data event listener is added to the call stack.
- The event loop moves the calbback function for data event listener to the event queue (task queue).
- Each chunk of data triggers a data event on the response object.
- Once the event loop detects the data event, the event loop will move the callback function for data event listener from the event queue (task queue) to the call stack to be executed and create a new function execution context for callback function.
- The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Data event listener callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes function execution context for callback function from the call stack.
- The data event listener also has no more code to run.
- The event loop removes function execution context for data event listener from the call stack.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Check Phase
- No check callbacks to execute.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- Close Callbacks Phase
- When the entire file is read, the event loop will move the callback function for close event listener from the event queue (task queue) to the call stack to be executed and create a new function execution context for callback function.
- The event loop executes
console.log
function call, a function execution context forconsole.log
is added to the call stack. - The event loop logs
"Close callback"
to the console. - The event loop removes function execution context for
console.log
from the call stack. - The callback function has no more code to run.
- The event loop removes function execution context for callback function from the call stack.
- The event loop checks for any new callbacks added to the microtasks queue.
- If no any new callbacks added to the microtasks queue, the event loop continues to next phase.
- The first loop starts by running the microtasks queue.