javascript event loop - in detail.

explaining event loop, call-stack, task queue, microtask queues and much more intricacies of node.js or most of the js runtime envs.

javascript is a single threaded. which means, even if the machine it’s running on has 16 cores, it’ll utilize only one core. javascript executes code line by line. but what if you have an db or an api call, does the code execution stop there and we all snort ***** until the response comes.
obviously, that’s not the case (for both).

here is where event loop and it’s friends enter the scene, and adds the ability of being async to js.
here’s the basic skeleton diagram :

image01

woah, a lot of words . let’s cut open them one by one.

call-stack : stores the tasks to be done, like console.log(), a response from an api call etc.

💡
“stack” : using the stack data structure, last in first out. the task that’s most recent will be executed first.

web-apis : these are the api’s provided by the browser to offload some work to browser like making api calls, setting timers. some ex. are setTimeout(), fetch(), setInterval() and many more. these offload these tasks to browser to do.

now the question comes, where does the response goes after browser has done it’s thing and gave us a response.
if the response is any of the below mentioned types :

// promises callbacks
.then(() => {...});
.catch(() => {...});
.finally(() => {...});

// or 

async func Function(){
    await (
        // function body
    )
}

// or

queueMicrotask(() => {...});
// learn more : https://developer.mozilla.org/en-US/docs/Web/API/Window/queueMicrotask

// or

new MutationObserver(() => {...}); 
// learn more : https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

// keep in mind that only the callbacks are pushed onto the microtask queue.

then, microtask queue handles them and other tasks like setTimeout(), are handled by the task queue (or macrotask queue).

🚨
microtasks are given higher priority than other tasks.

event loop just does, what it’s name implies. it just loops through the tasks in microtask and macrotask queues. first, it goes through microtasks, when it’s empty it goes through the macrotask queue. these tasks go to call-stack and executed.

let’s understand with a simple example, javascript will go line by line through the program :

// example.js 

// to call-stack 
console.log('start');

// to macrotask queue
setTimeout(() => {
  console.log('first timeout');
}, 0);

// to microtask queue
Promise.resolve().then(() => {       
  console.log('the promise');
});

// to macrotask queue
setTimeout(() => {
  console.log('second timeout');
}, 0);

// to call stack 
console.log('end');

the result will be :

start
end
the promise
first timeout
second timeout

thats all !

more resources to learn :

philip roberts(jsconf eu 2014) : https://www.youtube.com/watch?v=8aGhZQkoFbQ
lydia hallie : https://www.youtube.com/watch?v=eiC58R16hb8

if you find any good resources lmk in the comments. i’ll add them here.