Key Components of the Event Loop
- Call Stack: The call stack is a data structure that keeps track of function calls. When a function is called, it is added to the top of the stack. When the function completes, it is removed from the stack.
- Web APIs: These are browser-provided APIs, such as
setTimeout
,DOM events
, andfetch
. When an asynchronous operation is initiated, it is handled by these Web APIs. - Task Queue (Callback Queue): When asynchronous operations complete, their callbacks are added to the task queue. The event loop picks tasks from this queue and pushes them to the call stack for execution.
- Microtask Queue: This queue holds microtasks, which are tasks scheduled to run immediately after the currently executing script finishes. Promises and
MutationObserver
are examples of microtasks.
How the Event Loop Works
- Execution Context: When a script starts executing, the call stack initially contains the global execution context. Function calls create new execution contexts pushed onto the stack.
- Asynchronous Operations: Asynchronous tasks are sent to Web APIs. Once these tasks complete, their callbacks are placed in the appropriate queue (task queue or microtask queue).
- Task Execution: The event loop constantly checks the call stack. If it is empty, it looks at the microtask queue. If the microtask queue is also empty, it then processes tasks from the task queue.
Practical Example
Consider the following code:
console.log('Start');
setTimeout(() => {
console.log('Timeout');
}, 1000);
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => response.json())
.then(data => console.log('Fetch:', data.title));
Promise.resolve().then(() => {
console.log('Promise');
});
console.log('End');(code-box)
Execution Flow:
- Console Log 'Start': Synchronously logs 'Start'.
- Set Timeout:
setTimeout
starts the timer and passes the callback to the Web API. The callback will move to the task queue after 1000 ms. - Fetch API Call: Initiates an HTTP request handled by the browser. Once the request completes, its
.then
callbacks are scheduled as microtasks. - Promise: Immediately resolved and its
.then
callback is added to the microtask queue. - Console Log 'End': Synchronously logs 'End'.
- Promise Callback: The event loop processes the microtask queue and logs 'Promise'.
- Fetch Callback: Once the fetch request completes, its
.then
callbacks are processed, logging the fetched data. - Timeout Callback: After 1000 ms, the timer expires and the callback logs 'Timeout'.
Output:
StartEndPromiseFetch: sunt aut facere repellat provident occaecati excepturi optio reprehenderitTimeout(code-box)
This example demonstrates how the event loop handles synchronous code, microtasks (Promise), and macrotasks (setTimeout).
Importance of the Event Loop
Understanding the event loop is at most crucial for optimizing JavaScript code performance and ensuring a smooth execution of asynchronous operations. It helps in writing non blocking code, prevents user interface (UI) freezes and enhance user experience
Conclusion
The JavaScript event loop is a powerful feature that allows asynchronous programming despite JavaScript’s single-threaded nature. By managing the execution of tasks efficiently, the event loop ensures that web applications remain responsive and perform well. Mastering the event loop is essential for any JavaScript developer aiming to build high-performance, scalable applications.