Photo by Jeremy Perkins on Unsplash

Single-threaded but Asynchronous: The JavaScript Event Loop

At this point in your JavaScript journey, you have probably heard that JavaScript is a single-threaded language. This is correct; JavaScript is a single-threaded language that executes code sequentially. This means that only one block of code can be running at a time in the JavaScript runtime environment (we will be using V8 as our example environment). The synchronous nature of JavaScript can lead to an issue aptly called “blocking” when a slow operation is running.

As a modern JavaScript developer, this may make you stop in your tracks once you think about what is happening in the apps you develop. If JavaScript is truly synchronous, how do our apps display almost instantaneously on the page even though we have to run expensive operations such a HTTP request? In a synchronous runtime, we would have to wait for the request to resolve before we can move on to the next operation needed to render our page. This would lead to slow UI load times and totally degrade the UX of our app. The worst case scenario is that our HTTP request never resolves and our page hangs waiting for a response.

In a truly single-threaded environment, this is how JavaScript would operate. Luckily, the modern web presents developers with a whole host of tools that allow us to execute tasks asynchronously. JavaScript, along with our browser environment, combine forces by using the Call Stack, Web APIs, the Event Queue, and the Event Loop to manage our asynchronous tasks.

The Call Stack

JavaScript uses a single Call Stack to manage the current code that is executing in the script. You can think of the Call Stack like a stack of books. Last in, first out. Each new book you receive is added to the top of the stack. Before you can read a book on the bottom of the stack, you first need to read all of the books on top of it. One can’t just pull a book from the bottom of the stack or it will fall down and break the stack.

JavaScript adds functions to the Call Stack as they are invoked. These are often referred to as “frames” on the Call Stack. Once the function completes execution, the evaluation of that function is returned and the function is popped off the call stack. If a function happens to call another function, this function will be placed on top of the function that is running, blocking the current function from running, and executing until completion. This is where blocking comes into play on JavaScript’s single-thread.

Web APIs and Asynchronous Programming

So why aren’t all of our apps suffering from blocking? Isn’t JavaScript single-threaded? The web runs on JavaScript! What are we missing?

Well, our browser environment gives us access to a multitude of Web APIs (e.g. setTimeout, fetch, and MediaStream) and asynchronous programming features which let our JavaScript code run as through it’s multi-threaded. We can also use Async/Await or Promises to tell the browser that we would like to offload this work to the browser. JavaScript can then offload functions that may cause blocking to the Web API until they have resolved.

Event Queue

Let’s say we make an asynchronous HTTP request for a large image. Our JavaScript will keep executing synchronously the whole time in the main thread while we wait for our image request to be fetched and returned to the Web API. While waiting for a response, our main code isn’t blocked but now we have an asynchronous function floating in the ether once the HTTP request is resolved.

So we have two processes running concurrently, we have our main JavaScript thread and the Web API thread. At this point, we need to send our function back into the main thread to integrate with our app, but we also can’t just inject the asynchronous function back into the call stack and interrupt the main thread.

This is where the Event Queue comes into play. A queue is a first in, first out data structure. You can think of it like the line at an amusement park. The first person in line is the first person to get on the ride. All of our asynchronous functions are added to the end of the Event Queue as they complete.

Event Loop

And now we have the glue which holds it all together, the Event Loop. The event loop is exactly what it sounds like, a loop! You can think of it as a continuously spinning ferris wheel. It’s a looping process that lets the Event Queue know when it’s safe to execute our asynchronous function in the main thread.

On each loop, the Event Loop does two things:

  1. It checks if there are Frames currently on the Call Stack
  2. It checks to see if there are any asynchronous functions waiting in the Event Queue.

At this point, our asynchronous HTTP request for the image has been sent to the Event Queue after being received from the server. The Event Loop keeps tabs on the Call Stack and waits for the right time to send out asynchronous function back to the Call Stack. Once the Event Loop sees that the Call Stack doesn’t have anymore Frames on it, the first asynchronous function (remember: First In, First Out!) in the Event Queue is sent back to the Call Stack where it originated to be executed. The function is now processed just like any other operation in JavaScript.

Conclusion

The JavaScript Event Loop is a powerful tool in modern web development that leverages features of our scripting language and runtime environment to help us build seamless non-blocking user experiences. While most of this process is abstracted during development, it is always a plus to know how our apps are working under the hood.

Note: Node.js also has an event loop that works outside of the browser. More information here.

Resources:

Articles:

MDN: Event Loop

MDN: Web APIs

W3Schools: Web APIs

MDN: Async/Await

MDN: Asynchronous Programming

JavaScript Visualized: Event Loop by Lydia Hallie

Understanding the Event Loop

Videos:

What is the JavaScript Event Loop really about? — JavaBrains

JavaScript Question: An Event Loop Problem — All Things JavaScript

What the heck is an event loop anyways? — Philip Roberts

Software Engineer. Former creative professional. Photographer. Fly-fisherman.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store