The JavaScript event loop is a fundamental mechanism that enables JavaScript to handle asynchronous operations, such as network requests, user inputs, timers, and other events, without blocking the main thread. Here’s an explanation of how it works:
1. Call Stack
The call stack is a data structure that keeps track of the functions that are being executed. When a function is invoked, it is added (pushed) to the top of the stack. When the function finishes execution, it is removed (popped) from the stack. JavaScript is single-threaded, meaning it can only execute one function at a time on the call stack.
2. Heap
The heap is an area in memory where objects are stored. While the call stack stores function calls, the heap stores objects, arrays, and other dynamic data structures. The heap is used by JavaScript for memory management.
3. Event Queue (or Message Queue)
The event queue is where events (like user input, timers, etc.) and their associated callback functions wait to be executed. Whenever an asynchronous operation completes, its callback is placed in the event queue.
4. Web APIs (Browser APIs)
Web APIs are provided by the browser (or Node.js APIs, if running in a server environment). They handle tasks like timers (setTimeout
, setInterval
), HTTP requests (via fetch
or XMLHttpRequest
), DOM events (like click
or keyup
), and more. These tasks are executed outside the JavaScript engine, usually by the browser or Node.js.
5. The Event Loop
The event loop is responsible for checking the call stack and event queue:
- If the call stack is empty, the event loop takes the first event from the event queue and pushes it to the call stack, executing its associated callback function.
- The event loop continually checks the call stack to see if it’s empty. If the stack is not empty, it waits.
In short, the event loop ensures that JavaScript doesn’t get blocked by asynchronous tasks by allowing it to continue executing other code while waiting for events.
6. Microtask Queue
There is a priority queue known as the microtask queue, which has higher priority than the event queue. Microtasks include Promises
and MutationObserver
callbacks. If a microtask is scheduled, the event loop will first empty the microtask queue before processing the next event from the event queue.
Flow of Execution in the Event Loop:
- Synchronous Code: The JavaScript engine executes synchronous code first. This means it runs all code in the call stack.
- Asynchronous Operations: When an asynchronous operation (like
setTimeout
or a network request) is encountered, it is passed to the relevant Web API to be handled. - Callback Queues: Once an asynchronous operation completes, its callback function is pushed to the event queue or microtask queue (depending on its nature).
- Event Loop: The event loop checks the call stack and executes the first callback in the queue if the stack is empty. If there are microtasks, they are executed first.
#javascript
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("End");
Execution flow:
"Start"
is logged first because it’s synchronous.setTimeout
is placed in the Web API queue with a 0ms delay.- The
Promise.resolve()
immediately resolves, placing its.then()
callback in the microtask queue. "End"
is logged next because it’s synchronous.- Since the microtask queue has a higher priority, the promise callback logs
"Promise"
before any event queue callbacks. - After the microtasks are executed, the event loop picks the
setTimeout
callback from the event queue and logs"Timeout"
.
Final Output:
#sql
Start
End
Promise
Timeout
Key Points:
- The event loop continuously monitors the call stack and event queue.
- Asynchronous tasks, like
setTimeout
andPromise
, are handled outside the main execution thread. - Microtasks are given priority over events in the event queue.
- JavaScript executes synchronous code first, then moves on to asynchronous tasks in the queue.
The event loop allows JavaScript to be non-blocking and highly responsive, even though it’s single-threaded.
Best Practices for Implementing Coding Filters!
To get the most out of coding filters, it’s essential to follow best practices when implementing them. This includes writing reusable filter functions, keeping logic modular, and ensuring that filters are applied consistently throughout your codebase. These practices improve code quality and make it easier to scale and maintain.