Asynchronous Javascript Part 2: The Event Loop
By: Kabir Nazir
Tags: JavaScript, Asynchronous, Event Loop

This article is Part 2 of a four-part series on Asynchronous Javascript. You can view Part 1 here.

As we have seen in our previous article, Javascript always jumps to the execution of the function at the top of the call stack. How does Javascript get notified of when a new function is added/removed to the stack? How does it know when to pause the execution of the current function and jump to the execution of a new function? All this is possible due to a component of Javascript called the event loop.

Event Loop

The event loop is one of the most important components of Javascript that we need to know in order to fully understand the execution flow. As the name suggests, it is a loop that runs over and over again, checking if there’s at least one function in the call stack, and if so, jumps the program execution to that of the function at the top of the call stack.

Let us try to understand the event loop better with an example

Output:

4

3

1

5

2

If you’re confused by the order of execution, read on. As you can see, we have three function declarations as well as a number of statements and function calls. Let us go line by line in the program execution. At the start of the program, the event loop of the Javascript is created and is started. The event loop first checks if there’s any function in the call stack. Our call stack currently looks like this:

| |

| |

| |

| |

| |

|_____________|



Call stack

Since the call stack is empty, the program continues its execution onto line 1, where the function sayOne is defined. Since it’s only a definition, the program just saves the function’s code in a variable called sayOne and moves on. At this point, the event loop again checks if there’s a function in the call stack. Since the call stack is still empty, the program moves on to the next line, which is 6. Here, the same steps of actions are repeated where function definition of sayTwo is saved and then the event loop checks the call stack again. The program then moves to line 10 where the same steps repeat for function sayThree.

The program then moves to line 14, where it encounters a statement for the first time. Do keep in mind that the call stack is still empty at this stage. Before executing the console.log statement to print “4" onto the console, the event loop checks if the call stack is empty. Since it is, the program goes ahead with the execution and prints 4 onto the console. The program then moves onto line 15 where it sees that the sayOne function has been called. Hence, it immediately adds this function to the call stack which now looks like this.

| |

| |

| |

| |

| sayOne() |

|_____________|



Call stack

Before moving on to line 16, the event loop is fired once more to check if the call stack is non-empty. Since the call stack is now not empty, the program then decides to execute the function that is at the top of the call stack i.e. sayOne. When the code of sayOne is being run, in line 2, we see that the sayThree function is being called and hence it gets added to the call stack.

| |

| |

| |

| sayThree() |

| sayOne() |

|_____________|



Call stack

Before moving on to line 3 in the sayOne function, the event loop is fired once more to check if the stack is non-empty. When it finds out it is, it does two actions at this moment. It first retrieves the function at the top of the stack and then checks to see if the currently running function is the same as it or not. If it was the same, it continues the execution of the current function. If they are not the same (which in our case, they are not), then the program pauses the execution of the current function and jumps to the execution of the topmost function (which is sayThree in this case). So, in line 11, before executing the console.log statement, the event loop once again checks for a non-empty stack, retrieves the topmost function, finds out it is the same as the currently running function and so resumes its code. Line 11 gets called (which results in the console.log statement printing “3" onto the console. Since we have reached the end of function sayThree, it is now removed from the call stack.

| |

| |

| |

| |

| sayOne() |

|_____________|



Call stack

The execution of the program now returns back to the previous function, which is the sayOne function. At this point, we should note that the execution of this function resumes from where we left it, which is just before line 3. The event loop is fired once again and finds out the stack is non-empty. It sees that the topmost function in the stack is the same as the currently running function sayOne and hence resumes. Line 3 gets called which prints “1” onto the console. We have reached the end of function sayOne and it is promptly removed from the call stack.

| |

| |

| |

| |

| |

|_____________|



Call stack

The program execution then moves back to where it left off from its previous function (which is the global context, in this case). So, the program now returns back to just before line 16. Now the event loop is fired again and it finds out that the call stack is empty. So, it moves on to executing line 16, which prints “5” onto the console.

The rest of the program proceeds like how we discussed so far. At line 17, the sayTwo function gets added to the call stack.

| |

| |

| |

| |

| sayTwo() |

|_____________|



Call stack

The event loop checks the call stack and runs the sayTwo function. This prints “2” onto the console. The sayTwo function is then removed from the call stack.

| |

| |

| |

| |

| |

|_____________|



Call stack

The event loop is fired again and when it sees that the stack is empty, it checks if there is any more code to be run in the current function. Since there is none, the program finally terminates.