Asynchronous JavaScript & EVENT LOOP from scratch 🔥 | Namaste JavaScript Ep.15
Understanding the Event Loop in JavaScript
Introduction to the Event Loop
- The video aims to clarify concepts like the event loop, callback queue, and microtask queue in JavaScript, which are often misunderstood by developers.
- Acknowledges that 90% of JavaScript developers struggle with these topics; watching this video will help viewers join the knowledgeable 10%.
Basics of JavaScript Execution
- JavaScript is a synchronous, single-threaded language with one call stack where all code execution occurs.
- When a program runs, a global execution context is created and pushed onto the call stack for line-by-line execution.
Function Invocation and Call Stack Behavior
- Upon invoking a function (e.g., function A), an execution context for that function is created and pushed onto the call stack.
- After executing all lines within function A, its context is popped off the call stack, followed by popping off the global execution context once all code has run.
Limitations of Call Stack
- The primary role of the call stack is to execute tasks quickly without waiting; it cannot handle delayed executions directly.
- If a script needs to wait (e.g., execute after five seconds), additional mechanisms beyond the call stack are required.
Introducing Timers and Browser Capabilities
- To manage time-based operations in JavaScript, timers provide necessary functionality outside of what the call stack can do.
- The browser contains not only the JavaScript engine but also local storage and timer capabilities essential for web applications.
Browser as a Powerful Tool
- Browsers facilitate communication with external servers (e.g., fetching data from Netflix), showcasing their remarkable capabilities.
- Beyond basic functions, browsers offer access to various features such as Bluetooth and geolocation services.
Accessing Super Powers in JavaScript
Introduction to Web APIs
- The speaker introduces the concept of "super powers" that JavaScript can access through a connection with the browser, emphasizing the need for Web APIs to utilize these capabilities.
Understanding Web APIs
- The speaker clarifies that
setTimeout,document.getElementById,fetch, andlocalStorageare not part of JavaScript itself but rather part of domain-specific APIs provided by browsers.
- Even
console.logis identified as a web API, highlighting that these functionalities are accessible due to browser integration rather than being inherent to JavaScript.
Role of the Browser
- The browser acts as an intermediary, granting access to various super powers like timers and DOM manipulation through its own set of APIs.
- The global object in browsers is referred to as "window," which provides access to all these super powers within the JavaScript engine.
Accessing Super Powers via Global Object
- To use features like timers or local storage, one typically uses syntax such as
window.setTimeout. However, since they exist in the global scope, they can also be accessed simply by their names (e.g.,setTimeout).
- The speaker explains that using just
setTimeoutor other similar functions is equivalent to prefixing them withwindow., thanks to how browsers encapsulate these functionalities.
Execution Context and Code Example
- When executing JavaScript code, a global execution context is created. This context allows for line-by-line execution of code.
- An example begins with logging "start" using
console.log, demonstrating how this call interacts with the console API provided by the browser.
Utilizing setTimeout
- The next line involves calling
setTimeout, which registers a callback function and starts a timer without blocking subsequent code execution.
Understanding JavaScript Execution Context and Event Loop
The Global Execution Context and Timers
- The global execution context is created when JavaScript code runs, managing the call stack. Once all code executes, this context is removed from the stack.
- A timer counts down from 5 seconds (5,000 milliseconds). Upon expiration, a callback function must be executed within the call stack.
- The event loop and callback queue are introduced to manage how callbacks are handled after timers expire.
Callback Queue and Event Loop Mechanics
- When the timer expires, the callback function moves to the callback queue instead of directly entering the call stack.
- The event loop acts as a gatekeeper that checks for functions in the callback queue and pushes them into the call stack for execution once it's clear.
Executing Callbacks
- After being pushed into the call stack by the event loop, an execution context for the callback function is created. It executes line by line.
- For example, a console log statement within this callback logs "call back" to the console.
Example: Event Listeners in Browsers
- An example involving an event listener on a button illustrates how JavaScript interacts with web APIs when handling events like clicks.
- As with any JavaScript code execution, a global execution context is created first. This context manages subsequent operations including logging messages to console.
Understanding DOM API Interaction
- The
document.getElementByIdmethod accesses elements in HTML through DOM API provided by browsers.
- Using
addEventListener, a click event handler registers a callback function that will execute upon clicking a button.
Registering Callbacks
Understanding the Event Loop in JavaScript
The Global Execution Context and Event Handlers
- The global execution context is removed from the stack after all tasks are executed, but event handlers remain in the web APIs environment until explicitly removed or the browser is closed.
- Registered callback methods wait for user interaction (e.g., button clicks) to be executed, remaining idle in the web APIs environment until triggered.
The Role of the Event Loop
- The event loop continuously monitors both the call stack and callback queue, ensuring that when the call stack is empty, it can push functions from the callback queue into execution.
- When a callback method is executed, it runs line by line and then disappears from both the call stack and callback queue once completed.
Importance of Callback Queue
- A callback queue is necessary to manage multiple rapid user interactions (e.g., multiple button clicks), preventing overload on the call stack.
- If a user clicks a button several times quickly, multiple callbacks will accumulate in the queue. The event loop processes these one at a time as space becomes available in the call stack.
Real-Life Application of Callbacks
- In real applications, numerous event listeners and timers exist; thus, managing them through a callback queue allows orderly processing without overwhelming JavaScript's single-threaded nature.
Fetch API and Promises
- Unlike traditional event listeners or setTimeout functions, fetch requests operate differently by returning promises that require callbacks to handle resolved data.
- Fetch initiates an API request while registering its associated callback function within web APIs. This function waits for data before being pushed to execute.
Example with Set Timeout and Fetch
- An example illustrates how both setTimeout and fetch register their respective callbacks within web APIs while maintaining separate timers for execution readiness.
Understanding Callback Functions and Event Loop
Fetching Data from Servers
- The fetch function initiates a network call to Netflix servers, which returns data within 5-50 milliseconds.
- Once the data is received, the callback function (CBF) is prepared for execution but does not immediately enter the callback queue.
Microtask Queue vs. Callback Queue
- The microtask queue exists alongside the callback queue but has higher priority for executing functions.
- Functions related to promises and certain other tasks are placed in the microtask queue, while standard callbacks go into the callback queue.
Execution Flow of Code
- While waiting for code execution, if there are many lines of code still running, it can delay when CBF gets executed despite receiving a response quickly.
- If a timer expires during this time, its corresponding callback (CBT) also waits in the callback queue until the main thread is free.
Event Loop Mechanism
- The event loop continuously checks if the call stack is empty; once it is, it processes tasks from both queues based on their priority.
- After executing all pending tasks in the microtask queue first (like CBF), it then executes tasks from the callback queue (like CBT).
Key Insights on Microtasks
- Only specific callbacks such as those from promises and mutation observers are placed in the microtask queue due to their higher priority.
Understanding the Event Loop and Task Queues in JavaScript
The Structure of Task Queues
- The event loop manages two main queues: the callback queue (also known as the task queue) and the microtask queue. The callback queue handles general callbacks, while the microtask queue is specifically for promises and mutation observers.
- If there are multiple microtasks pending in the microtask queue, the event loop will only process tasks from the callback queue after all microtasks have been completed.
Microtasks and Starvation
- When a microtask executes, it can create additional microtasks. This can lead to a situation where tasks in the callback queue may never get executed if new microtasks keep being generated, resulting in "starvation" of those tasks.
- Starvation occurs when tasks in the callback queue are indefinitely delayed due to continuous execution of newly created microtasks. This phenomenon highlights an important aspect of how JavaScript prioritizes its task handling.
The Role of JavaScript Engine
- While much focus is on browser capabilities and web APIs, it's crucial not to underestimate the JavaScript engine itself, which performs significant work behind the scenes.
- Future discussions will delve deeper into understanding JavaScript engines, including their architecture and how they differ from JavaScript runtimes. This exploration aims to clarify misconceptions about what happens within these engines.
Conclusion and Engagement