Understanding the Event Loop in JavaScript

During my five years as a technical lead, I’ve interviewed a number of JavaScript developers, and one concept that seems to give a hard time to a lot of beginners is the event loop. It’s one of the core concepts of JavaScript and one that is known for being hard to understand.

There are a lot of articles and videos on the topic, but in this one, I’ll try to break down the concept using small, easy-to-understand code snippets. I hope by the end of the article; you will have a good understanding of what is the event loop and what role it plays in JavaScript.

JavaScript Is Single

You may or may not already know that JavaScript is a single-threaded programming language. In other words, it can do one thing at a time. Multi-threaded languages, on the other hand, are capable of performing multiple tasks in different threads simultaneously.

Let's try to visualize the call stack for a typical JavaScript program.

function c() {
  console.log("C")
}

function b() {
  console.log("B")
  c()
}

function a() {
  console.log("A")
  b()
}

a()

// A
// B
// C

Now, the call stack for this code may look something like the following:

call stack

The first entry in the call stack will be the source file itself. The,n the next item is the call to function a() , and inside that function, there is a call to the console.log() function, which prints out “A” on the screen and immediately returns.

call stack

A function stays in the stack until all its operations are done, and that’s why function a() stays in the stack. After the console.log() call, there is a call to the function b() so that’ll be pushed into the call stack.

call stack

Just like the previous state, the console.log() call prints out “B” on the screen and returns immediately. Again the function b() stays in the stack, and a call to the function c() takes place.

call stack

After the last call to the console.log() returns, calls to function c(), function b(), function a() will return in the top to bottom order, and finally, the source file will be popped out of the stack.

Now, let’s have a look at a different code snippet.

setTimeout(function() {
  console.log("A")
}, 5000);

console.log("B")

// B
// A

In this one, you’re setting a timer of 5 seconds on the first console.log() call. Since JavaScript is single-threaded, what should happen is the execution should stop for 5 seconds before printing out “A” on the printout “A” and then printing out “B” to the console.

But what happens is “B” gets printed to the console immediately, then after 5 seconds, “A” gets printed to the console. So the setTimeout() gets pushed into the stack and then popped out.

The console.log() call takes place, prints the “B” on the console, and then after 5 seconds, the console.log() call inside the setTimeout() callback comes back to existence, prints out “A” on the console, and returns.

The question is, where did the callback go in the first place, and how did it come back automatically in the future? Let me explain.

The JavaScript Runtime

In order to run JavaScript code, you need a runtime. People often confuse a runtime with an engine. An engine is a program that can read your JavaScript code, parse it, and turn it into runnable commands.

The runtime, on the other hand, provides JavaScript with necessary external APIs so that it can communicate with the outside world. For example, both Google Chrome and Node.js use V8 as their engine, but they have different runtimes.

In Google Chrome, you get things like the window object or the DOM to resonate with the changes your code makes to the user. in Node.js, you get the global object, and there is no DOM at all.

Built-in functions like setTimeout() is not part of the engine itself. Rather it comes as a part of the runtime. So when you call setTimeout() in your code, the engine doesn’t handle the call. Instead, the engine delegates the work to the runtime.

Once the timer task has been delegated to the runtime, the engine is free to do more tasks. So it goes ahead and executes the next console.log() call and prints out “B” on the console.

After 5 seconds, the timer times out, and instead of pushing the previous console.log() call back to the stack, it gets pushed into something called a task queue which is also a part of the runtime.

The event loop sits between the event queue and the call stack and checks whether the call stack is empty or not. The moment the stack queue is empty, the event loop pulls any remaining task from the task queue and chugs it into the call stack.

The call stack then processes the console.log() call and prints out “A” on the screen. So the event loop in JavaScript is actually one of the puzzle pieces that build up the JavaScript runtime.

Conclusion

Thanks a lot for taking an interest in my writing. I hope that I’ve taught event loop and a few other JavaScript concepts that you may not have known before. Feel free to reach out on Twitter or LinkedIn if you have any questions. Until the next one, stay safe and keep learning.

Farhan Hasin Chowdhury
Farhan Hasin Chowdhury
Senior Software Engineer

Farhan is a passionate full-stack developer and author. He's a huge fan of the open-source mindset and loves sharing his knowledge with the community.

Expertise
  • Laravel
  • MySQL
  • Vue.js
  • Node.js
  • AWS
  • DigitalOcean
  • Kubernetes
  • AWS RDS
  • MongoDB
  • Python
  • Elastic Beanstalk
  • AWS S3
  • AWS CloudFront
  • Redis
  • Express.js
  • Amazon EC2
  • PostgreSQL
  • FastAPI
  • GitLab CI/CD
  • JavaScript
  • PHP
  • +16

Ready to start?

Get in touch or schedule a call.