DEV Community

TusharShahi
TusharShahi

Posted on

UI Blocking behaviour: microtasks vs macrotasks

Can you find the difference between the two code snippets below:

function handleClick1() {
     setTimeout(handleClick1, 0);
}

function handleClick2() {
     Promise.resolve().then(handleClick2);
}
Enter fullscreen mode Exit fullscreen mode

If you are not able to identify the implications of choosing one over the other, then this blog post will teach you something new.

Background

setTimeout is for scheduling a callback after a certain amount of time. Promise.resolve().then will do the same thing effectively, but internally both are different. The latter returns a promise, that is already resolved. Calling then(callback) on that promise will schedule callback to be executed.

So both the above functions call themselves recursively with minimal delay. The difference is that callback from setTimeout is placed in macrotask queue and a callback from a promise.then() is placed in microtask queue. How the event loop treats items from these two queues is what makes the above 2 code snippets the difference.

Event loop treatment of microtask vs macrotask

All an event loop does is while there are tasks to perform, it performs them and then sleeps and waits for other tasks.

Macrotasks (or simply tasks) include functions responsible for work such as:

  1. Parsing
  2. Reacting to DOM,

among others...

After the execution of a task picked from the task queue, the event loop performs a microtask checkpoint. The algo for which is something like:

While microtask queue is not empty, pick the oldest task from microtask queue and execute it.
Enter fullscreen mode Exit fullscreen mode

What this means is that if a microtask enqueues another microtask that task will be executed before the next macrotask. And since UI rendering is a macrotask, it will never be executed by the event loop.

Here is a demo for the above: JS Bin demo. An infinite animation is running. If we trigger handleClick1 then we add some processing to the main thread, but the animation still renders correctly. But if we trigger handleClick2 the animation stops.

I have added the variable totalCount, so we can break before the page crashes. But what is noticeable is that once the microTask loop is started, the UI becomes unresponsive for some time.. Because tasks like rendering, reacting to DOM etc. will only be executed after the microtask queue is empty.

This makes handleClick1 from the above code snippet a safer choice. Hope the blog helped explain one fundamental difference between microtasks and macrotasks.

Top comments (0)