Event loop in JavaScript
In this tutorial, you’ll learn about the event loop in JavaScript.
JavaScript single-threaded model
JavaScript is a single-threaded programming language. In other words, it can do only one thing at a time.
A thread of execution is the smallest sequence of programmed instructions that can be managed independently by a scheduler. A programming language is single-threaded means it can only perform one task or operation at a single time. This means it would execute an entire process from start to end without the thread being interrupted or stopped.
JavaScript engine executes a script from the top and works its way down creating execution contexts and pushing and popping functions onto and off the call stack.
How is JavaScript asynchronous and single-threaded?
The event loop is the secret behind JavaScript’s asynchronous programming. JS executes all operations on a single thread, but using a few smart data structures, gives us the illusion of multi-threading. Let’s take a look at what happens on the back-end.
The event loop concept is very simple. There’s an endless loop, where the JavaScript engine waits for tasks, executes them, and then sleeps, waiting for more tasks.
Basic Architecture
- Memory Heap: Objects are allocated in a heap which is just a name to denote a large mostly unstructured region of memory
- Call Stack: This represents the single thread provided for JavaScript code execution. Function calls form a stack of frames. It is responsible for keeping track of all the operations in line to be executed. Whenever a function is finished, it is popped from the stack. It is a LIFO queue (Last In, First Out).
- The browser or Web APIs: They are built into your web browser and are able to expose data from the browser and surrounding computer environment and do useful complex things with it. They are not part of the JavaScript language itself, rather they are built on top of the core JavaScript language, providing you with extra superpowers to use in your JavaScript code.
- Event or Callback Queue: It is responsible for sending new functions to the track for processing. It follows the queue data structure to maintain the correct sequence in which all operations should be sent for execution.
Whenever an async function is called, it is sent to a browser API. These are APIs built into the browser. Based on the command received from the call stack, the API starts its own single-threaded operation.
An example of this is the setTimeout
method. When a setTimeout
operation is processed in the stack, it is sent to the corresponding API which waits till the specified time to send this operation back in for processing.
Where does it send the operation? The event queue. Hence, we have a cyclic system for running async operations in JavaScript. The language itself is single-threaded, but the browser APIs act as separate threads.
The event loop facilitates this process. It has one simple job — to monitor the call stack and the callback queue. If the call stack is empty, the event loop will take the first event from the queue and will push it to the call stack, which effectively runs. If it is not, then the current function call is processed.
Let’s quickly take a look at an example and see what’s happening when we’re running the following code in a browser:
Output:
First
Third
Second
- We invoke
bar
.bar
returns asetTimeout
function. - The callback we passed to
setTimeout
gets added to the Web API, thesetTimeout
function andbar
get popped off the call stack. - The timer runs, in the meantime
foo
gets invoked and logsFirst
.foo
returns (undefined),baz
gets invoked, and the callback gets added to the queue. baz
logsThird
. The event loop sees the call stack is empty afterbaz
returned, after which the callback gets added to the call stack.- The callback logs
Second
.
Let’s take a look at a visual representation
Conclusion
The Event Loop is an infinite loop that keeps waiting for a queue (sometimes referred to as the Callback Queue or Event Queue) to be filled with tasks. As and when the callback queue gets filled up with a task, the Event Loop kicks in and removes the task based on FIFO (First In First Out) from the Callback Queue. It is then pushed onto the Call Stack which executes the task.