
Introduction
JavaScript is single-threaded this means that the main thread on which code is executed runs one line at a time. There is no possibility of doing anything in parallel. Therefore, the run time is blocked until a task is completed. An example of blocking the run time is an infinite loop. However, the DOM API, setTimeout() , setInterval() methods are provided by the web API to allow us to write asynchronous non-blocking code.
What is the event loop ?
Code execution flow is based on a concept called an event loop. While there are tasks (code to be executed) the JavaScript engine will execute the tasks starting with the oldest task first. Event handlers, loading external scripts, setInterval(), and setTimeout() methods are a few examples of such tasks.
The event loop is a constantly running process that will check if the call stack is empty. We learned about the call stack in detail in section 8.1. Let’s understand this with an example:
function funcHello() { console.log('hello'); } setTimeout(funcHello, 3000); console.log('hi');
//The order of the console.log statements will be: "hi" "hello"
Function funcHello() is declared within global scope. After which the setTimeout() method is encountered. This method is provided by the browser API. It will delay tasks without blocking the main thread. The method accepts a callback function as an argument (funcHello()) and a second parameter (3 seconds) after which the callback function should be added to the event queue. funcHello() is added to the event queue after 3 seconds. The event queue is also called the callback queue, as the name suggests it is a list/queue of callback functions. It will remain there till the call stack is empty. When all the functions in the call stack are empty i.e. previously invoked functions have been popped off, and the statement console.log(‘hi’) has finished executing, then the first item in the event queue (funcHello()) will be added to the top of the call stack. The event queue follows the FIFO principle (First In First Out). The first item in the event queue is pushed to the call stack. The callback function is then invoked, returns a value, and gets popped off the call stack.
This process of monitoring the call stack and moving tasks from the event queue to the call stack is the event loop.
Let’s have a look at another example:
function func1(){ console.log('function 1'); } function func2(){ console.log('function 2'); } setTimeout(func1, 5000); func2();
In the above example we have two functions, func1() and func2().The function func1() is passed to the setTimeout() method which will execute the func1() function after 5 seconds. Let’s examine how the function calls will execute:
- Initially the call stack and queue are empty
- The setTimeout() method is invoked and a timer runs in the browser
- The callback function func1 passed to the setTimeout() method is added to the event queue after 5 seconds, where it will wait until the call stack is empty.
- In the meantime the function call func2() is added to the call stack first. And the statement log(‘function 2’) is added to the top of the previous frame. The JavaScript engine executes the top frame (console.log(‘ function 2’)) and func2() is popped from the call stack
- Then the first item in the event queue which is func1() is popped and pushed to the call stack and the statement log(‘function 1’) will be executed
The order of the statements logged to the console are:
"function 2" "function 1"
Therefore the event loop monitors the call stack and event queue. When the call stack is empty, it will take an event (a callback function) from the event queue and push it to the call stack. Then the call stack executes the event/function and pops it off the call stack. Each such cycle is called a tick.