Ever struggled with managing async logic in JavaScript and felt like callbacks and promises just weren’t cutting it? Let me introduce you to an increasingly popular pattern: **Async Generators**. Async generators are like the cool versatile sibling of regular generators and async functions rolled into one. They allow you to yield promises over time, which means you can produce a stream of asynchronous values — ideal for things like reading large files chunk-by-chunk, lazy-loading data, or handling events where you don’t want to wait for everything before proceeding. Here’s a simple example to demonstrate: ```javascript async function* fetchDataInChunks(url) { const response = await fetch(url); const reader = response.body.getReader(); while(true) { const { done, value } = await reader.read(); if (done) break; yield new TextDecoder().decode(value); } } // Consuming the async generator (async () => { for await (const chunk of fetchDataInChunks('https://lnkd.in/g5V2Uq4w')) { console.log('Received chunk:', chunk); } })(); ``` What’s happening here? - The async generator function `fetchDataInChunks` reads a stream from a fetch response in chunks. - Each chunk is yielded as it arrives—without waiting for the entire file. - The consuming code uses `for await...of` to process each chunk asynchronously. Why should you care? - This pattern is becoming more relevant as web APIs push for streaming and real-time data handling. - It helps avoid loading big payloads entirely into memory, improving performance and user experiences. - It makes your async code cleaner and easier to reason about compared to nested callbacks or promise chaining. Bonus tip: Combine async generators with `AbortController` to cancel streaming operations gracefully — great for UIs where users might navigate away mid-download. Async generators are still a bit underutilized outside advanced use cases, but trust me, they’ll become a powerful tool in your JavaScript toolbox as streaming data becomes the norm. Give it a try next time you work with live data or streaming APIs! #JavaScript #AsyncProgramming #WebDevelopment #CodingTips #TechTrends #SoftwareEngineering #ModernJS #DeveloperExperience
How to use Async Generators for Streaming Data in JavaScript
More Relevant Posts
-
🚀 Understanding Callbacks, Promises, and Async/Await in JavaScript JavaScript is single-threaded but asynchronous — meaning it can only execute one piece of code at a time, yet still handle tasks like API calls, file reads, or timers without blocking other code. To manage these async operations, JavaScript gives us three main tools: 👉 Callbacks 👉 Promises 👉 Async/Await 🧩 1. Callbacks A callback is a function passed into another function, to be executed later when an operation finishes. function fetchData(callback) { console.log('Fetching data...'); setTimeout(() => { callback('Data received!'); }, 2000); } fetchData((data) => { console.log(data); }); While callbacks work, they can lead to deeply nested and hard-to-read code — aka “callback hell.” getUser(id, (user) => { getPosts(user.id, (posts) => { getComments(posts[0].id, (comments) => { console.log(comments); }); }); }); ⚡ 2. Promises A Promise represents a value that will be available now, later, or never. It has three states: pending, fulfilled, or rejected. function fetchData() { return new Promise((resolve, reject) => { console.log('Fetching data...'); setTimeout(() => { resolve('Data received!'); }, 2000); }); } fetchData() .then((data) => console.log(data)) .catch((error) => console.error(error)); Promises made async code more readable and improved error handling — but there’s an even cleaner way 👇 🧠 3. Async/Await Introduced in ES2017, async and await make asynchronous code look and behave more like synchronous code. function fetchData() { return new Promise((resolve) => { setTimeout(() => { resolve('Data received!'); }, 2000); }); } async function getData() { console.log('Fetching data...'); const data = await fetchData(); console.log(data); } getData(); Error handling is also cleaner with try...catch: async function getData() { try { const data = await fetchData(); console.log(data); } catch (error) { console.error('Error:', error); } }
To view or add a comment, sign in
-
-
Day 77 of 100DaysOfCode – Understanding Async/Await, JS Engine & Geolocation API 🌍 Let’s break down three key JavaScript concepts every developer should understand 👇 🔹 1. What Is Async/Await, and How Does It Work? JavaScript is asynchronous — meaning it doesn’t wait for long tasks like fetching data or file reading to finish before moving on. That’s where async/await shines. It makes async code look simple and readable, like synchronous code. async function delayedGreeting(name) { console.log("A Messenger entered the chat..."); await new Promise(resolve => setTimeout(resolve, 2000)); console.log(`Hello, ${name}!`); } delayedGreeting("Alice"); console.log("First Printed Message!"); Here, the function pauses for 2 seconds before greeting Alice — but the rest of the program keeps running! We can also handle errors neatly using try/catch: async function fetchUserData() { try { let response = await fetch(`https://lnkd.in/dWvHabH4); let userData = await response.json(); console.log(userData); } catch (error) { console.log("Error fetching user data:", error); } } Async/await = cleaner syntax + better error handling ✨ 🔹 2. How Does the JavaScript Engine Work (and What Is a Runtime)? Think of the JavaScript engine as the “brain” that reads, understands, and executes your code. For example, Google Chrome and Node.js use the V8 Engine. When you run: const greeting = "Hello, World!"; console.log(greeting); The engine: Parses the code (checks for errors) Compiles it into machine-readable bytecode Executes it to print “Hello, World!” But the JavaScript runtime is more than just the engine — it’s the whole environment your code runs in. In the browser → runtime includes the DOM, Fetch API, and timers. In Node.js → runtime includes file systems, HTTP, etc. So the engine executes, while the runtime provides tools to interact with the outside world 🌍 🔹 3. What Is the Geolocation API and How Does getCurrentPosition Work? The Geolocation API lets websites request your location — but only with your permission (for privacy reasons). Example: navigator.geolocation.getCurrentPosition( (position) => { console.log("Latitude: " + position.coords.latitude); console.log("Longitude: " + position.coords.longitude); }, (error) => { console.log("Error: " + error.message); } ); This uses your device’s GPS, Wi-Fi, or IP address to determine your location. You get a position object that contains details like: latitude longitude accuracy altitude, and more. Always explain why your app needs location data and how it’ll be used — user trust is key. 💡 Wrap-Up: Async/Await simplifies asynchronous programming. JavaScript Engine executes code; Runtime gives it superpowers. Geolocation API helps apps know “where” the user is — responsibly.
To view or add a comment, sign in
-
🚀 𝐌𝐚𝐬𝐭𝐞𝐫𝐢𝐧𝐠 𝐂𝐚𝐥𝐥𝐛𝐚𝐜𝐤 𝐅𝐮𝐧𝐜𝐭𝐢𝐨𝐧𝐬 𝐢𝐧 𝐉𝐚𝐯𝐚𝐒𝐜𝐫𝐢𝐩𝐭 Ever wondered how JavaScript handles tasks without blocking the main thread? That’s where 𝐂𝐚𝐥𝐥𝐛𝐚𝐜𝐤 𝐅𝐮𝐧𝐜𝐭𝐢𝐨𝐧𝐬 come into play! ⚙️ 🧩 What is a Callback Function? 𝐀 𝐜𝐚𝐥𝐥𝐛𝐚𝐜𝐤 𝐟𝐮𝐧𝐜𝐭𝐢𝐨𝐧 𝐢𝐬 𝐚 𝐟𝐮𝐧𝐜𝐭𝐢𝐨𝐧 𝐩𝐚𝐬𝐬𝐞𝐝 𝐚𝐬 𝐚𝐧 𝐚𝐫𝐠𝐮𝐦𝐞𝐧𝐭 𝐭𝐨 𝐚𝐧𝐨𝐭𝐡𝐞𝐫 𝐟𝐮𝐧𝐜𝐭𝐢𝐨𝐧 — 𝐚𝐧𝐝 𝐢𝐬 𝐢𝐧𝐭𝐞𝐧𝐝𝐞𝐝 𝐭𝐨 𝐛𝐞 “𝐜𝐚𝐥𝐥𝐞𝐝 𝐛𝐚𝐜𝐤” 𝐥𝐚𝐭𝐞𝐫 𝐛𝐲 𝐭𝐡𝐚𝐭 𝐟𝐮𝐧𝐜𝐭𝐢𝐨𝐧. 💡 Since functions in JavaScript are First-Class Citizens, they can be treated like values — passed around, returned, or assigned to variables. 📖 Think of it like this: You give function 𝐗 the responsibility to call function𝐘 later. So,𝐘becomes the callback of𝐗. ----------------------------------------------------- ⏱️ Callbacks in Action: Handling Asynchronous Operations JavaScript is 𝐬𝐢𝐧𝐠𝐥𝐞-𝐭𝐡𝐫𝐞𝐚𝐝𝐞𝐝, but callbacks allow it to perform non-blocking tasks like API calls, timers, or event handling. Here’s a simple example 👇 console.log("Start"); setTimeout(() => { console.log("⏰ This runs after 2 seconds"); }, 2000); console.log("End"); 🧠 Output: Start End ⏰ This runs after 2 seconds 💬 Explanation: When 𝐬𝐞𝐭𝐓𝐢𝐦𝐞𝐨𝐮𝐭 is called, the callback goes into the Web API environment. The JS engine keeps running other code (non-blocking). After the timer expires, the callback moves to the 𝐂𝐚𝐥𝐥𝐛𝐚𝐜𝐤 𝐐𝐮𝐞𝐮𝐞. It’s executed only when the Call Stack is empty, ensuring smooth asynchronous flow. 𝐓𝐡𝐚𝐭’𝐬 𝐭𝐡𝐞 𝐦𝐚𝐠𝐢𝐜 𝐨𝐟 𝐜𝐚𝐥𝐥𝐛𝐚𝐜𝐤𝐬 𝐞𝐧𝐚𝐛𝐥𝐢𝐧𝐠 𝐚𝐬𝐲𝐧𝐜 𝐛𝐞𝐡𝐚𝐯𝐢𝐨𝐫 𝐢𝐧 𝐚 𝐬𝐢𝐧𝐠𝐥𝐞-𝐭𝐡𝐫𝐞𝐚𝐝𝐞𝐝 𝐰𝐨𝐫𝐥𝐝! ✨ -------------------------------------------------- 🔒 𝐂𝐚𝐥𝐥𝐛𝐚𝐜𝐤𝐬 + 𝐂𝐥𝐨𝐬𝐮𝐫𝐞𝐬 = 𝐈𝐧𝐭𝐞𝐫𝐯𝐢𝐞𝐰 𝐆𝐨𝐥𝐝 💬 Here’s a classic interview problem 👇 𝐏𝐫𝐨𝐛𝐥𝐞𝐦: If you try to use a global counter variable, you risk having it modified by other parts of the code. A better solution is needed to keep the counter private and persistent. 𝐒𝐨𝐥𝐮𝐭𝐢𝐨𝐧 (𝐂𝐥𝐨𝐬𝐮𝐫𝐞): By creating a function that wraps the counter and the event listener attachment, the event handler (the callback) forms a closure over the local variable (count). 𝐟𝐮𝐧𝐜𝐭𝐢𝐨𝐧 𝐡𝐚𝐧𝐝𝐥𝐞𝐂𝐥𝐢𝐜𝐤() { 𝐥𝐞𝐭 𝐜𝐨𝐮𝐧𝐭 = 0; 𝐝𝐨𝐜𝐮𝐦𝐞𝐧𝐭.𝐠𝐞𝐭𝐄𝐥𝐞𝐦𝐞𝐧𝐭𝐁𝐲𝐈𝐝("𝐛𝐭𝐧").𝐚𝐝𝐝𝐄𝐯𝐞𝐧𝐭𝐋𝐢𝐬𝐭𝐞𝐧𝐞𝐫("𝐜𝐥𝐢𝐜𝐤", 𝐟𝐮𝐧𝐜𝐭𝐢𝐨𝐧() { 𝐜𝐨𝐮𝐧𝐭++; 𝐜𝐨𝐧𝐬𝐨𝐥𝐞.𝐥𝐨𝐠("𝐁𝐮𝐭𝐭𝐨𝐧 𝐜𝐥𝐢𝐜𝐤𝐞𝐝", 𝐜𝐨𝐮𝐧𝐭, "𝐭𝐢𝐦𝐞𝐬"); }); } 𝐡𝐚𝐧𝐝𝐥𝐞𝐂𝐥𝐢𝐜𝐤(); 🧩 Explanation: The inner callback function forms a closure over the variable count. Even after handleClick() finishes executing, count stays alive in the callback’s Lexical Environment. This keeps the counter private, persistent, and secure — no memory Leaks. #JavaScript #WebDevelopment #LearningInPublic #NamasteJavaScript #FrontendDevelopment #CodingJourney
To view or add a comment, sign in
-
Optional chaining is one of JavaScript's most useful features. But what's the performance impact? TL;DR it's massive. I recently collaborated with Simone Sanfratello on detailed benchmarks comparing noop functions to optional chaining, and the results were revealing: noop functions are 5.5x to 8.8x faster. Running 5 million iterations clearly showed the differences. Noop functions achieved 939M ops/sec as the baseline. Optional chaining with empty objects ran at 134M ops/sec (7x slower). Optional chaining with an existing method reached 149M ops/sec (6.3x slower). Deep optional chaining was the slowest, at 106M ops/sec (8.8x slower). The explanation comes down to what V8 must do. Noop functions are inlined by V8, making them essentially zero-overhead. The function call vanishes in optimized code. Optional chaining requires property lookup and null/undefined checks at runtime. V8 can't optimize these away because the checks must occur each time. This is why Fastify uses the abstract-logging module. Instead of checking logger?.info?.() throughout the code, Fastify provides a noop logger object with all logging methods as noop functions. The key is to provide noops upfront rather than checking for existence later. When logging is disabled, V8 inlines these noop functions at almost zero cost. With optional chaining, runtime checks are required every time. One reason for excessive optional chaining is TypeScript's type system encourages defensive coding. Properties are marked as potentially undefined even when runtime guarantees they exist, causing developers to add ?. everywhere to satisfy the type checker. The solution is better type modeling. Fix your interfaces to match reality, or use noop fallbacks like "const onRequest = config.hooks.onRequest || noop" and call it directly. Don't let TypeScript's cautious type system trick you into unnecessary defensive code. Context matters, though. Even "slow" optional chaining executes at 106+ million operations per second, which is negligible for most applications. Use optional chaining for external data or APIs where the structure isn't controlled, in normal business logic prioritizing readability and safety, and to reduce defensive clutter. Use noop functions in performance-critical paths, when code runs thousands of times per request, in high-frequency operations where every microsecond counts, and when you control the code and can guarantee function existence. Even a few thousand calls per request make the performance difference significant. My advice: don't optimize prematurely. Write your code with optional chaining where it enhances safety and clarity. For most applications, the safety benefits outweigh the performance costs. If profiling reveals a bottleneck, consider switching to noop functions. Profile first, optimize second. Remember: readable, maintainable code often surpasses micro-optimizations. But when those microseconds matter, now you understand the cost.
To view or add a comment, sign in
-
-
Ever hit a wall trying to handle asynchronous operations in JavaScript and wished you had a cleaner, more intuitive way to manage your async workflows? Enter \*\*Async Iterators\*\*—a modern JavaScript feature that’s incredibly useful but still flying under the radar for many devs. You’re probably familiar with Promises and async/await for handling async tasks. But what if you want to process data streams—like user input events, API paginated data, or reading files chunk-by-chunk—asynchronously and \*\*sequentially\*\*? That’s where Async Iterators shine. ### What are Async Iterators? Simply put, Async Iterators let you loop over asynchronous data sources with a syntax very similar to synchronous `for..of` loops—but they wait for each promise to resolve before proceeding. Instead of handling callbacks or chaining Promises manually, your code becomes more linear and easier to read. Here’s a quick demo: ```javascript async function\* fetchNumbers\(\) \{ let n = 1; while \(n \<= 5\) \{ await new Promise\(r =\> setTimeout\(r, 500\)\); // simulate async delay yield n++; \} \} \(async \(\) =\> \{ for await \(const num of fetchNumbers\(\)\) \{ console.log\(num\); // prints numbers 1 through 5 with half-second pauses \} \}\)\(\); ``` Notice the `for await…of` syntax, which waits for each yielded Promise from `fetchNumbers` before printing and moving to the next? ### Why it matters - \*\*Clean asynchronous loops:\*\* No more juggling array callbacks with Promises. - \*\*Smooth handling of data streams:\*\* Perfect for paginated APIs or real-time data feeds. - \*\*Improved readability:\*\* Async code flows left to right without nested callbacks. ### Practical scenario Imagine consuming a third-party API that sends you records in pages. Instead of manually fetching page after page with chained Promises, you can wrap that into an Async Iterator that \*yields\* each record as soon as it arrives, and consume it with a simple loop. Async Iterators bring a powerful, expressive way to handle asynchronous operations that feel synchronous on the outside. If you haven’t tried them, give it a spin—you might wonder how you lived without them! Have you used Async Iterators for your projects? What new async problem will you tackle next? Drop your thoughts! #JavaScript #AsyncProgramming #WebDevelopment #CodingTips #ModernJS #DeveloperExperience #TechTrends
To view or add a comment, sign in
-
💡 JavaScript Series | Topic 2 | Part 3 — The Event Loop, Promises & Async/Await — The Real Concurrency Engine of JavaScript👇 If you’ve ever wondered how JavaScript handles multiple tasks at once even though it’s single-threaded — the secret lies in its Event Loop. 🌀 ⚙️ 1️⃣ JavaScript’s Single Threaded Nature JavaScript runs on one thread, executing code line by line — but it uses the event loop and callback queue to handle asynchronous tasks efficiently. console.log("Start"); setTimeout(() => console.log("Async Task"), 0); console.log("End"); 🧠 Output: Start End Async Task ✅ Even with 0ms, setTimeout goes to the callback queue, not blocking the main thread. 🔁 2️⃣ The Event Loop in Action Think of it as a traffic controller: The Call Stack runs your main code (synchronous tasks). The Callback Queue stores async tasks waiting to run. The Event Loop constantly checks: 👉 “Is the stack empty?” If yes, it moves queued tasks in. That’s how JS achieves non-blocking concurrency with a single thread! 🌈 3️⃣ Promises — The Async Foundation Promises represent a value that will exist in the future. They improve callback hell with a cleaner, chainable syntax. console.log("A"); Promise.resolve().then(() => console.log("B")); console.log("C"); 🧠 Output: A C B ✅ Promises go to the microtask queue, which has higher priority than normal callbacks. ⚡ 4️⃣ Async / Await — Synchronous Power, Asynchronous Core Async/Await is just syntactic sugar over Promises — it lets you write async code that looks synchronous. async function getData() { console.log("Fetching..."); const data = await Promise.resolve("✅ Done"); console.log(data); } getData(); console.log("After getData()"); 🧠 Output: Fetching... After getData() ✅ Done ✅ The await keyword pauses the function execution until the Promise resolves — but doesn’t block the main thread! 💥 5️⃣ Event Loop Priority When both microtasks (Promises) and macrotasks (setTimeout, setInterval) exist: 👉 Microtasks always run first. setTimeout(() => console.log("Timeout"), 0); Promise.resolve().then(() => console.log("Promise")); 🧠 Output: Promise Timeout 🧠 Key Takeaways ✅ JavaScript runs single-threaded but handles async operations efficiently. ✅ The Event Loop enables concurrency via task queues. ✅ Promises and Async/Await simplify async code. ✅ Microtasks (Promises) have higher priority than Macrotasks (Timers). 💬 My Take: Understanding the Event Loop is what turns a JavaScript developer into a JavaScript engineer. 👉 Follow Rahul R Jain for real-world JavaScript and React interview questions,hands-on coding examples, and performance-driven frontend strategies that help you stand out. #JavaScript #FrontendDevelopment #WebDevelopment #AsyncProgramming #Promises #AsyncAwait #EventLoop #Coding #ReactJS #NodeJS #NextJS #WebPerformance #InterviewPrep #DeveloperCommunity #RahulRJain #TechLeadership #CareerGrowth
To view or add a comment, sign in
-
⚛️ Full-Stack Bridge: The JavaScript Foundation of React We all write JSX, but to build robust Complex AI Systems, we must know the source: React is a programmatic interface built entirely on JavaScript functions. This post reveals the blueprint behind your UI. (P.S. Advanced topics like TSX, AOT compilation, and component structure are already in the roadmap!) 1. The React Element: The Pure JavaScript Blueprint The JSX you write is merely syntactic sugar for React's foundational API: the React.createElement() function. This function does NOT create a DOM element. Instead, it creates a lightweight, plain JavaScript Object—the React Element. This object is the definitive blueprint for your UI. The structure is simple and functional: React.createElement(Tag/Type, Props, Children) JSX's final form: a programmatic object. const blueprint = React.createElement( 'div', { id: 'parent' }, // Props are simple JS objects React.createElement('h1', {}, "Dynamic H1!") ); Key Insight: Since the UI is defined by code, we can use native JavaScript logic (loops, variables) to dynamically generate structures before rendering, making our UI 100% logic-driven. 2. ReactDOM: The Dedicated Renderer If the React Element is the blueprint, ReactDOM is the execution crew. Its sole purpose is managing the slow, heavy Document Object Model (DOM). ReactDOM.createRoot() sets the entry point (the bridge to your HTML). root.render(element) takes the JavaScript object blueprint and applies the necessary changes to the Real DOM. This separation ensures performance: React works with fast JS objects, and ReactDOM ensures that the DOM is only updated efficiently when absolutely necessary. 3. Why This Foundation is Critical for AI This architecture is key to our Full-Stack Bridge: Precursor to Performance: The React Element object is the Virtual DOM. This enables the Reconciliation algorithm, minimizing DOM updates. Zero Lag UI: The user is waiting only for the ML API call, not a laggy interface. The logic is fast; only the network call is the bottleneck. Challenge: How many createElement() function calls would a button with an icon inside it require?
To view or add a comment, sign in
-
🍏 JavaScript Daily Bite #8: Understanding Constructors Prototypes allow us to reuse properties across multiple instances — especially for methods. Constructor functions take this further by automatically setting the [[Prototype]] for every object created. ⚙️ Constructor Functions Constructors are just functions called with the new operator. Every instance created from a constructor automatically inherits from its prototype property. Key Concepts Constructor.prototype becomes the [[Prototype]] of all instances Constructor.prototype.constructor references the constructor function itself Returning a non-primitive from a constructor overrides the default instance 🧩 Classes vs Constructor Functions ES6 classes are syntactic sugar over constructor functions — the underlying behavior is the same. You can still manipulate Constructor.prototype to modify behavior across all instances. 🔧 Mutating Prototypes Since all instances share the same prototype object, mutating it changes behavior for every instance. However, reassigning the entire Constructor.prototype object is problematic because: Older instances will still reference the old prototype The constructor link may be lost, breaking user expectations and built-in operations 🧱 Constructor Prototype vs Function Prototype Constructor.prototype is used when creating instances. It’s separate from Constructor.[[Prototype]], which points to Function.prototype. ⚙️ Implicit Constructors of Literals Literal syntaxes in JavaScript automatically set their [[Prototype]]: Object literals → Object.prototype Array literals → Array.prototype RegExp literals → RegExp.prototype This is why array methods like map() or filter() are available everywhere — they live on Array.prototype. 🚫 Monkey Patching Warning Extending built-in prototypes (e.g., Array.prototype) is dangerous because it: Risks forward compatibility if new methods are added to the language Can “break the web” by changing shared behavior The only valid reason is for polyfilling newer features safely. 🧬 Building Longer Inheritance Chains Constructor.prototype becomes the [[Prototype]] of instances — and that prototype itself can inherit from another. Default chain: instance → Constructor.prototype → Object.prototype → null To extend the chain, use Object.setPrototypeOf() to link prototypes explicitly. In modern syntax, this corresponds to class Derived extends Base. ⚠️ Avoid legacy patterns: Object.create() can build inheritance chains but reassigns prototype, removes constructor, and can introduce subtle bugs. ✅ Best practice: Mutate the existing prototype with Object.setPrototypeOf() instead. 🌱 Next in the Series → Functions & Prototypes: A Deeper Dive #JavaScript #WebDevelopment #Frontend #Programming #LearnToCode #TechEducation #SoftwareDevelopment #JSDailyBite
To view or add a comment, sign in
-
🔥 𝐀𝐬𝐲𝐧𝐜𝐡𝐫𝐨𝐧𝐨𝐮𝐬 𝐉𝐚𝐯𝐚𝐒𝐜𝐫𝐢𝐩𝐭 & 𝐄𝐕𝐄𝐍𝐓 𝐋𝐎𝐎𝐏 — 𝐄𝐱𝐩𝐥𝐚𝐢𝐧𝐞𝐝 𝐟𝐫𝐨𝐦 𝐒𝐜𝐫𝐚𝐭𝐜𝐡! ⚙️ 𝐓𝐡𝐞 𝐉𝐚𝐯𝐚𝐒𝐜𝐫𝐢𝐩𝐭 𝐄𝐧𝐠𝐢𝐧𝐞 𝐚𝐧𝐝 𝐂𝐚𝐥𝐥 𝐒𝐭𝐚𝐜𝐤 • JavaScript is a synchronous, single-threaded language, meaning it has one Call Stack where all code execution happens sequentially, one line at a time. • Execution starts with the Global Execution Context being pushed onto the Call Stack. • Function invocations also create their own execution contexts which are pushed onto and then popped off the Call Stack. -------- 🌐 𝐁𝐫𝐨𝐰𝐬𝐞𝐫 𝐒𝐮𝐩𝐞𝐫𝐩𝐨𝐰𝐞𝐫𝐬 (𝐖𝐞𝐛 𝐀𝐏𝐈𝐬) • The browser (or Node.js environment) provides extra capabilities beyond the JavaScript engine, known as Web APIs. • Examples of Web APIs include: setTimeout, the DOM (Document Object Model), fetch (for network requests), and localStorage. • These APIs allow JavaScript code to perform non-blocking (asynchronous) task. ------- 🔁 𝐓𝐡𝐞 𝐄𝐯𝐞𝐧𝐭 𝐋𝐨𝐨𝐩, 𝐂𝐚𝐥𝐥𝐛𝐚𝐜𝐤 𝐐𝐮𝐞𝐮𝐞, 𝐚𝐧𝐝 𝐌𝐢𝐜𝐫𝐨𝐭𝐚𝐬𝐤 𝐐𝐮𝐞𝐮𝐞 • When an asynchronous function like 𝐬𝐞𝐭𝐓𝐢𝐦𝐞𝐨𝐮𝐭 or an 𝐞𝐯𝐞𝐧𝐭 𝐥𝐢𝐬𝐭𝐞𝐧𝐞𝐫 (𝐚𝐝𝐝𝐄𝐯𝐞𝐧𝐭𝐋𝐢𝐬𝐭𝐞𝐧𝐞𝐫) is encountered: 1. The function itself is handled by the browser's Web API environment. 2. The callback function (the code to be executed later) is registered. • Once the 𝐚𝐬𝐲𝐧𝐜𝐡𝐫𝐨𝐧𝐨𝐮𝐬 𝐭𝐚𝐬𝐤is complete (e.g., the timer expires, or a button is clicked): The registered callback function is moved to the 𝐂𝐚𝐥𝐥𝐛𝐚𝐜𝐤 𝐐𝐮𝐞𝐮𝐞 (𝐚𝐥𝐬𝐨 𝐤𝐧𝐨𝐰𝐧 𝐚𝐬 𝐭𝐡𝐞 𝐓𝐚𝐬𝐤 𝐐𝐮𝐞𝐮𝐞 𝐨𝐫 𝐌𝐚𝐜𝐫𝐨𝐭𝐚𝐬𝐤 𝐐𝐮𝐞𝐮𝐞). • The 𝐄𝐯𝐞𝐧𝐭 𝐋𝐨𝐨𝐩 is a continuously running process that checks two main things: • Is the Call Stack empty? (i.e., is all synchronous code finished executing?) • If the Call Stack is empty, are there any functions waiting in the Callback Queue or Microtask Queue? • If the Call Stack is empty, the Event Loop picks a function from the queues and pushes it onto the Call Stack for execution. --------- ⚡ 𝐌𝐢𝐜𝐫𝐨𝐭𝐚𝐬𝐤𝐬 𝐯𝐬. 𝐌𝐚𝐜𝐫𝐨𝐭𝐚𝐬𝐤𝐬 • 𝐌𝐢𝐜𝐫𝐨𝐭𝐚𝐬𝐤 𝐐𝐮𝐞𝐮𝐞 (Higher Priority): Holds callbacks from Promises (like .then() and .catch()) and Mutation Observers. •𝐂𝐚𝐥𝐥𝐛𝐚𝐜𝐤 𝐐𝐮𝐞𝐮𝐞 (Lower Priority): Holds callbacks from Web APIs like setTimeout, setInterval, and DOM event listeners. 1. 𝐌𝐢𝐜𝐫𝐨𝐭𝐚𝐬𝐤𝐬 𝐡𝐚𝐯𝐞 𝐚 𝐡𝐢𝐠𝐡𝐞𝐫 𝐩𝐫𝐢𝐨𝐫𝐢𝐭𝐲. The Event Loop will empty the entire Microtask Queue before it checks and pushes one single task from the Callback Queue onto the Call Stack. 2. If the Microtask Queue keeps adding new microtasks indefinitely, it can lead to 𝐒𝐭𝐚𝐫𝐯𝐚𝐭𝐢𝐨𝐧of the Callback Queue, preventing those tasks from ever running. -------- 🎥 Highly recommend this episode if you want to understand how JavaScript handles async code under the hood!⚡ https://lnkd.in/dpTTnJWx #JavaScript #NamasteJavaScript #EventLoop #WebDevelopment #AsyncJS #FrontendDevelopment #AkshaySaini #JavascriptMastery
To view or add a comment, sign in
-
More from this author
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development