JS illustrated: The event loop 🔁
Tags: javascript
Published: 2019-08-15 23:00:21

Javascript is single threaded, yet, developers can write asynchronous code in Javascript!

But how is it possible? The event loop makes it possible!

Before we start, lets define the environment in which the event loop operates. We assume that we are dealing with Javascript code that is executed by a browser (not in Node or other environment).

Lets meet the heros of our story

# The call stack

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/vt1lq8dr1xnia6p2u9cp.png)

The call stack is a place in memory that keeps track of the function executing at that time, and the functions that are going to be executed after that. Each function is placed on top of the previous function. The first function added, is going to be executed last (First in, last out).

# The web API

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/vuqg7xfop4hy8bvw3hu1.png)

The web API is not part of the core JS, instead, it provides various methods that can be used by a Javascript program, like <code>setTimeout()</code> or <code>alert()</code>.

# The message queue

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/t7p6bgzqu9q3h5j5gmsh.png)

The message queue is a list of messages, waiting to be executed by their associated functions. A new message is added to the list, each time an event, that has been watched by an event listener, occures.

# The event loop

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/jr8h8zb75ultqptp3r5o.png)

The event loop is a process that keeps running and checks whether the call stack is empty or not. If the call stack is empty, it pushes the first item of the message queue into the call stack for execution.

Here's the browser environment

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/uge9s4sxw8f2tf5nbjz6.png)

# A JS story

Lets take a look at the following code and see what happens

{% gist https://gist.github.com/kapantzak/5ce328a1de202301cd11d268d6588160 file=eventLoop1.js %}

Calling the <code>foo</code> function, the result is

    > One
    > Three
    > Two

Now, lets see our heros trying to execute the above code

First, the browser sends the <code>foo()</code> function call to the call stack.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/o48tslf0jdmadl13cvcn.png)

The <code>console.log("One")</code> statement gets pushed on top of the previous frame.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/0t69b2ogj37gkoaqusf1.png)

In the meanwhile, the event loop checks to see if the call stack is empty

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/65sj3txo63lvhnh6rotx.png)

The JS runtime executes the top frame and removes it from the call stack.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/wlgm90neatktrds37jok.png)

Continuing the execution, the browser sends the <code>setTimeout()</code> statement to the stack

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/o9ffcy95t6gl1rq1qrzk.png)

The event loop checks again

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ocd9j7fhuptra2q8kb9o.png)

The environment sets up a timer that is going to trigger the callback inside the <code>setTimeout</code>

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/tbre7v5gfg1zoiam0dw8.png)

and the next statement is pushed into the call stack

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/o007pzbfjrgbnavxuiel.png)

Here's the event loop again

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/zekyensfo6431nsjn6fw.png)

The event loop did not find an empty stack so it does nothing again. The execution continues with the next, and final, statement of the <code>foo()</code> function

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/eo7g60avq4bugbu8fqqk.png)

Lets get back to the web API, which set up a timer for a callback function. Now that the timer has ended, the browser sends the callback message to the message queue

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/f9upsh1ul4z9jwfp4qy9.png)

After the last statement got executed, it is removed from the stack, and, as soon as there is nothing else inside the <code>foo()</code> function declaration, the oldest <code>foo()</code> frame is removed from the call stack too!

Now, the event loop may be more lucky

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/hga1ny4nb18v07nu7zkt.png)

The event loop checks for any messages waiting in the queue

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/3z0tsghi3nj32nmaloxw.png)

and sends the message's associated function to the call stack

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/qso2vz6qwnav0ty1kuhq.png)

Finally, the JS runtime executes the last frame and removes it form the call stack

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/7iwx5zisofb9ffoqg17c.png)

# Resources
- [MDN: Concurrency model and Event Loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop)
- [Hackernoon: Understanding JS: The Event Loop (Alexander Kondov)](https://hackernoon.com/understanding-js-the-event-loop-959beae3ac40)
- [Medium: JavaScript Event Loop Explained (Anoop Raveendran
)](https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4)
- [Kyle Simpson, 2015, *You don't know JS: Async & Performance*, 5-7](https://www.amazon.com/You-Dont-Know-JS-Performance/dp/1491904224)