Can you find the difference between the two code snippets below:
function handleClick1() {
setTimeout(handleClick1, 0);
}
function handleClick2() {
Promise.resolve().then(handleClick2);
}
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:
- Parsing
- 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.
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)