DEV Community

Cover image for JavaScript Event Loop: Everything You Need To Know Explained Simply
Tolulope Olobayo
Tolulope Olobayo

Posted on • Edited on

JavaScript Event Loop: Everything You Need To Know Explained Simply

Microtask queues, task queues, call stacks, event loops, and JavaScript engines - what do all these confusing things have in common? Well, they all make JavaScript (JS) go. And by make JS go, I mean they all make JS work in the browser.

Today we’re going to learn all about the event loop in JavaScript! By the end of this article hopefully you’ll have a basic understanding of how the event loop works as well as the queues and stacks involved that make it happen, so let's get to it!

HOW JAVASCRIPT WORKS

Before we can understand how the event loop works, we first gotta understand how JavaScript works.

JavaScript is a single threaded language. What this means is that a JS program can only execute one thing at a time. When a script is run, JS will move through each line of code one after the other, executing each statement, and waiting for that statement to complete before moving on to the next.

Visualization of one line of code at a time

Under the hood, this line by line process is handled by the JS Engine. The JS engine is software that is responsible for parsing and executing JavaScript code.

To keep track of each statement that it is being run, the JS Engine uses something called a call stack. It’s a tool that stores information about all the calls that are made when completing the execution of a function.

When the JS Engine invokes a function it pushes it onto the call stack, it then executes the body of the function. Any inner function calls are pushed onto the stack and executed as well.

Visualization of functions being pushed onto the stack

Once a function is complete, it is popped off of the stack and the engine moves on to the next line of code. This process continues until the JS Engine reaches the last line of the script.

Visualization of functions being popped off of the stack

This way JS is able to focus on one thing at a time, doing it until completion and then moving onto the next thing in a synchronous fashion, one after the other.

Full visualization of entire script running, with functions being pushed on then popped off the stack when finished

Now this sounds great. It’s neat and tidy, and it gets the job done. Howeveeeer, it can also create some problems.

If there were to be a function or loop that literally takes forever to run, the program will be blocked and stuck at that point! The rest of the script will never execute.

Script stuck at in a loop

Blocking the script is a big no no. If we were to perform a task like fetching a photo from another source over the network in JS, it would cause the script to pause and wait for the photo to come. This could potentially cause a huge delay. And if it never comes, the script would be blocked. This makes it inadvisable to use JS to do these sort of blocking tasks.

So then how would we be able to use JS to run a function without blocking the execution of the script? Like somehow run the blocking function concurrently (at the same time) while the engine finishes the rest of the script? And what about stuff that we don’t want to to happen right then and there, but at a later time? For instance, showing a picture on the screen after 3 seconds. How would JS be able to handle that?

Both of these situations are examples of asynchronous events, they are initiated at one point, and they finish at another time, later in future. Unfortunately, JS is single threaded and synchronous! It only works in the here and now. It can't do things in parallel and it can’t handle future events, going back to execute code that it has already passed.

If that’s the case, then how would JS be able to make these asynchronous events happen?

SPOILER ALERT - it can’t!

At least not on its own.

JAVASCRIPT RUNS IN THE BROWSER ENVIRONMENT

JS can only do one thing at a time, but in the browser, we are able to use it to have multiple different things happen at once. Not only that, but we can use it to display things at different times. Page animations run, things suddenly popup, I can click things, I can scroll the page, and nothing is ever blocked. How is this possible?

Well, that, my friend, is because JS is not working alone!

When we write JS to create websites, all the JS that we write is run in the browser. Along with housing the JS Engine, the browser provides extra tools to help JS handle asynchronous events. These tools are called Web APIs.

In case you didn’t already know, functions like setTimeOut() and methods like addEventListener() are not actually JS! (😮🤭 I know!)

Rather they are Web APIs that we can use in JS to process these events in another place, asynchronously while the JS Engine is doing its thing.

When called, setTimeout function is handed off to web APIs, rest of script continues

Once an asynchronous event is done and ready to be executed, it needs some way of getting to the call stack so it can actually be run by the JS Engine.

This part is kinda complicated. You might have different things finishing at different times, so how everything is stored, managed, and sent to the call stack to be run presents a really tricky challenge.

That’s where the event loop comes in to save the day!!

WHAT IS THE EVENT LOOP?

The event loop is the process that coordinates asynchronous events in the browser.

The event loop is exactly what it sounds like — it’s a loop, or a set of steps that is scheduled to run continuously while a web page is open.

This process is usually handled by a program in your browser. For example, in Chrome, libevent is the software that handles the event loop.

SO HOW DOES THE EVENT LOOP WORK?

Once an asynchronous event like setTimeout is finished and ready to be executed, the callback function (aka task) will get added to something called a queue.

In computer science land, queues are very similar to stacks. They both are just structures used to store data. The only difference between them is the order in which you remove things.

Stacks follow Last In First Out (LIFO) removal order. So the last thing that was added (or pushed) to the stack will be the first thing removed (or popped off). Kind of like a stack of plates. The last plate added to the stack will be the first plate that is grabbed from it later on.

Stack of plates being added and removed

Queues, on the other hand follow First In First Out (FIFO) removal order, like an actual queue or line of people. The first person that gets in the line is the first that will be served and leaves it.

Line of female stick figures with figures entering and leaving the line

In the browser environment there are different queues for different things, but two that are important for the event loop to work are the task queue and the microtask queue.

When a task is ready to be executed the browser will add the callback from the Web API to either the task queue or microtask queue. Which queue a callback goes into depends on how important the task is. Tasks that we want to run as soon as possible are added to the microtask queue. Other tasks are added to the task queue.

Callback functions added to their respective queues

Once the main script has finished executing and the call stack is empty, the browser will call the event loop to run. The event loop will do the job of adding queued tasks to the call stack so that they can be executed. It will then wait for that task to finish and the call stack to empty, and then add the next task.

Event loop adds callbacks to the callstack to be run

Which queue the event loop pulls from depends on what tasks need to be done. Microtask events can be executed at any point once the call stack becomes empty, whereas task events are only executed once per iteration of the loop.

Every time the loop runs, only one task event will be executed. In contrast, multiple microtask events can be executed within a single iteration of the loop. This means microtasks can run between tasks like this:

promise callbacks in microtask queue execute before setTimeout callbacks in task queue

Although we start with two setTimeout callbacks, the promise callbacks execute before the last setTimeout callback because the call stack became empty. The event loop then iterates again and the final setTimout call back is executed.

This process will keep going on and on, with the event loop waiting for the call stack to empty then adding different queued tasks to the call stack as they appear.

And that’s it! That’s how the event loop works!

LET’S SUMMARIZE

Here are some quick definitions:

  • Call Stack - keeps track of function execution
  • JS Engine - parses and executes JS code (uses the call stack)
  • Microtask Queue - stores tasks that should be called in the most immediate future
  • Task Queue - stores other tasks to be executed later
  • The Event Loop - coordinates the process of transferring callbacks from tasks queues to the call stack (this allows JS to perform asynchronous events)

As different asynchronous events take place, like when you click a button in the webpage or when the browser needs to re render the the webpage to display changes, these events are added to their respective queues by the browser. The event loop then adds them to the call stack to be executed once it is clear.

Together the call stack and these queues are what the event loop uses to do its job, allowing JS to perform asynchronous tasks in the browser.

Pretty neat huh?

WORD OF CAUTION

While the process I’ve explained here is how browsers should run the event loop (according to the spec), not all browsers implement this process the same way. Some browsers may push events that are meant to be microtasks into the tasks queue instead. This results in varying order of task execution across browsers (See here for more information on that) .

Keep that in mind as you are developing things across different browsers in the wild!

LEARN MORE ABOUT THE EVENT LOOP

Hopefully now you have a better understanding of the event loop and how it works! Here are some additional resources that you can reference for more information or to expand your knowledge.

Top comments (4)

Collapse
 
ortonomy profile image
🅖🅡🅔🅖🅞🅡🅨 🅞🅡🅣🅞🅝

What a fantastic article. Well written, well researched, clear and to the point. 🔥

Collapse
 
ben profile image
Ben Halpern

Nice post!