DEV Community

Cover image for 🕒 Understanding the Event Loop and Concurrency Model in JavaScript
Dipak Ahirav
Dipak Ahirav

Posted on

🕒 Understanding the Event Loop and Concurrency Model in JavaScript

JavaScript is single-threaded, but it manages to handle asynchronous operations seamlessly. The magic behind this is the Event Loop. In this blog, we'll dive deep into how the Event Loop works and how JavaScript handles concurrency. 🧙‍♂️

please subscribe to my YouTube channel to support my channel and get more web development tutorials.

Image description

📜 Table of Contents

  1. Introduction
  2. Call Stack
  3. Web APIs
  4. Callback Queue
  5. Event Loop
  6. Microtasks and Macrotasks
  7. A Simple Example
  8. Conclusion

📚 Introduction

JavaScript’s concurrency model is based on an event loop, which allows it to perform tasks asynchronously, even though it runs on a single thread. This means it can handle many tasks at the same time without waiting for one to finish before starting another.

🏗️ Call Stack

The call stack is a simple data structure that keeps track of function calls. Think of it as a pile of books where you can only add or remove the book on top.

When a function is called, it’s added to the stack. When the function execution is complete, it’s removed from the stack.

function foo() {
  console.log('foo');
}

function bar() {
  foo();
  console.log('bar');
}

bar();
Enter fullscreen mode Exit fullscreen mode
  • When bar() is called, it goes on top of the stack.
  • Inside bar(), foo() is called, so it’s placed on top of bar().
  • When foo() finishes, it’s removed from the stack, and bar() continues.

🌐 Web APIs

JavaScript in browsers provides Web APIs for handling tasks like setTimeout, fetch, and DOM events. These APIs run in the background and, when tasks are completed, their callbacks are added to the Callback Queue.

🔃 Callback Queue

The Callback Queue (also known as the Task Queue) is where asynchronous callbacks from Web APIs wait to be executed.

When the call stack is empty, the Event Loop picks the first task from the Callback Queue and puts it on the call stack for execution.

🔄 Event Loop

The Event Loop is like a manager who keeps an eye on the call stack and the Callback Queue. Here’s how it works:

  1. The Event Loop looks at the call stack to see if it’s empty.
  2. If the stack is empty, it takes the first task from the Callback Queue and puts it on the stack.
  3. The task runs and is then removed from the stack.
  4. This process repeats.

🧩 Microtasks and Macrotasks

Tasks in JavaScript are divided into two categories: macrotasks and microtasks.

  • Macrotasks: These include setTimeout, setInterval, and I/O operations. They are placed in the Callback Queue.
  • Microtasks: These include Promise callbacks and MutationObserver. They are placed in the Microtask Queue.

Microtasks have a higher priority than macrotasks. They are executed right after the current task completes, before any macrotasks.

👨‍💻 A Simple Example

Let’s look at an example to see this in action:

console.log('Start');

setTimeout(() => {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(() => {
  console.log('Promise');
}).then(() => {
  console.log('Another Promise');
});

console.log('End');
Enter fullscreen mode Exit fullscreen mode

Step-by-Step Execution:

  1. console.log('Start') is added to the stack and runs immediately, logging "Start".
  2. setTimeout is called, which registers a task in the Web API to run after 0ms. Its callback is placed in the Callback Queue.
  3. Promise.resolve().then(...) creates a microtask. The callback for this microtask is placed in the Microtask Queue.
  4. console.log('End') is added to the stack and runs immediately, logging "End".

At this point, the stack is empty. The Event Loop checks the Microtask Queue first:

  1. The first promise callback runs, logging "Promise".
  2. The second promise callback runs, logging "Another Promise".

Finally, the Event Loop checks the Callback Queue:

  1. The setTimeout callback runs, logging "setTimeout".

Output:

Start
End
Promise
Another Promise
setTimeout
Enter fullscreen mode Exit fullscreen mode

🏁 Conclusion

Understanding the Event Loop and Concurrency Model is essential for writing efficient JavaScript code. By mastering these concepts, you can handle asynchronous operations better and build more responsive applications. 🌟

🚀 Happy Coding!

Feel free to leave your comments or questions below. If you found this guide helpful, please share it with your peers and follow me for more web development tutorials. Happy coding!

Follow and Subscribe:

Top comments (0)