How asynchronous code is executed in JavaScript
In JavaScript, asynchronous code is handled using the event loop, which allows non-blocking execution. JavaScript is single-threaded, meaning it can only perform one task at a time. However, it can handle asynchronous tasks efficiently without blocking the main thread by leveraging callback queues and promises.
1. Call Stack
JavaScript has a call stack where functions are added and executed in a Last In, First Out (LIFO) manner.
When a function is called, it is pushed onto the stack. Once it completes, it is popped off.
2. Web APIs (Browser or Node.js APIs)
- When JavaScript encounters asynchronous operations like
setTimeout
,fetch
, orEvent Listeners
, it offloads these to the browser (or Node.js) APIs. These operations run in the background, freeing up the main thread.
3. Callback Queue
- Once an asynchronous task completes, its callback is added to the callback queue (also called the task queue). This queue holds all callbacks that are waiting to be executed.
4. Event Loop
The event loop constantly monitors both the call stack and the callback queue.
If the call stack is empty (i.e., no functions are being executed), the event loop takes the first callback from the callback queue and pushes it to the call stack for execution.
5. Microtask Queue (for Promises)
Promises use a separate queue called the microtask queue. Tasks from this queue are given higher priority than those in the callback queue.
When a promise resolves (e.g., with
.then()
), its callback is placed in the microtask queue, and it runs before tasks in the callback queue.
Code Example
console.log('Start');
// Asynchronous operation using setTimeout
setTimeout(() => {
console.log('Timeout callback');
}, 0);
// Promise example
Promise.resolve().then(() => {
console.log('Promise resolved');
});
console.log('End');
Execution Flow:
console.log('Start')
is executed and prints "Start".setTimeout
is encountered. Its callback is sent to the browser’s Web API and scheduled for later (after 0 milliseconds in this case), and the function continues execution.The promise is resolved, and its
.then()
callback is placed in the microtask queue.console.log('End')
is executed, printing "End".The call stack is empty, so the event loop checks the microtask queue and runs the promise's callback, printing "Promise resolved".
Finally, the event loop checks the callback queue, finds the
setTimeout
callback, and prints "Timeout callback".
Output:
Start
End
Promise resolved
Timeout callback
Summary:
The call stack executes tasks sequentially.
Asynchronous tasks (like
setTimeout
or promises) are handled outside the call stack via Web APIs.Once the call stack is empty, the event loop pulls tasks from the microtask queue (for promises) first, then from the callback queue.
+-----------------+ +-----------------+
| | | |
| Call Stack |<--------| Event Loop |
| (Executes code) | | (Monitors stack |
| | | and queues) |
+-----------------+ +-----------------+
^ ^
| |
| |
+-----------------+ +--------------------+
| | | |
| Web APIs | | Callback Queue |
| (Async task | | (Holds callbacks |
| handling) |-------->| after async ops) |
| | +--------------------+
+-----------------+
^
|
+---------------------+
| |
| Microtask Queue |
| (Promises resolved |
| before callbacks) |
+---------------------+
How the flow works:
Call Stack: Executes synchronous code.
Web APIs: Handles async operations like
setTimeout
,fetch
, etc., outside the call stack.Callback Queue: Stores callbacks of async tasks to be executed later.
Microtask Queue: Stores promises' callbacks and is processed before the callback queue.
Event Loop: Monitors the call stack and moves tasks from the queues to the stack when the stack is empty.
Subscribe to my newsletter
Read articles from Bhupendra directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Bhupendra
Bhupendra
I'm a passionate software developer with a strong foundation in JavaScript, TypeScript, Node.js, and React. I've honed my skills in full-stack development and building scalable, user-friendly applications. I'm driven by creating innovative solutions that solve real-world problems and enhance user experiences. I'm a quick learner, constantly updating myself with the latest industry trends and best practices. Beyond technical skills, I value collaboration, problem-solving, and maintaining a growth mindset. I'm excited to contribute my expertise to a dynamic team and make a positive impact through technology.