Async operation in JS

JS has one call stack and the code written in it is the main execution thread and it ensures the concurrency. So if any operation(like async) blocks this call stack, it is called blocking the main thread. To ensure concurrency, JS has microtask queue and callback queue in its arsenal.

JavaScript is a single-threaded language, but using web API JavaScript can maintain its asynchronous function. When an asynchronous task comes to the call stack browser sets it into the #webAPI and then when the task is ready for execution, it is placed into the callback queue or microtask queue. The event loop is constantly checking if the call stack is empty or not. This is known as the concurrency model in JS. Because of this model, JS is able to perform async operations without blocking the main thread even though JS is a single single-threaded synchronous language.

Callback functions

It allows JS to access async functionality. It is called so as it will be called sometime later in your code depending upon where it is used.

Microtask queue

The microtask queue is used for tasks that need to be executed as soon as possible, such as promise resolutions and mutations to the DOM.

Mutation observer

it keeps on checking if there is any mutation in DOM tree, if yes, some CB function will be triggered.

Callback queue --> The callback queue is used for tasks that can be executed at a later time, such as click events and timers.

Event loop --> its job is to put CB function into call stack to get executed from CB queue as soon as Call stack is empty.

Settimeout

many times call stack has to deal with Web APIs like settimeout, DOM API, fetch, local storage, console etc. These are superpowers of browser and JS can access them using window object.

setTimeout(() =>{
    console.log("callback");
  }, 5000)

As soon as JS engine encounters setTimeout api, it will create a memory space for its callback, and then the JS engine will call `timer API and a timer of 5000 ms will start running. Meanwhile JS engine keeps on executing the next lines of code in the call stack.

When timer expires, the CB function is put inside CB queue. Note -> there is no guarentee that the code written in CB function will be executed after timer expires. It may take more time depending on when call stack is empty.

Event listeners

as soon as event listeners are defined, the cb function gets attached to that event. As soon as that event trigggers, the CB will go in callback queue.

Fetch api

fetch('api endpoint').then(cb(){})

JS engine will register the CB fn in webAPI environment. Fetch will make call to server and as soon as get it gets resolved response, the CB fn will not got in CB queue, instead it will go in microtask queue.

Suppose if a microtask creates another microtask, that will also become part of microtask queue. It may happen that CB fn in CB queue never get a chance to get executed. This is known as starvation of CB queue.

once JS finished executing all the code and call stack is empty, then event loop will first check in microtask queue and then if cb queue is empty, then it will look into the cb queue.

Event loop gives priority microtask queue over call back queue.`