In the following code:
setTimeout(() => console.log("hello"), 0);
Promise.resolve('Success!')
.then(console.log)
What should happen in my understanding:
print hello
directly added to callback queue as time is 0print Success!
added to callback queueIf I am not wrong, the callback queue is FIFO.
But the code output is:
Success!
hello
What is the explanation?
To slow down or delay processing in JavaScript, setTimeout function can be combined with async/await keywords to let our program take some breath before continuing to the next instruction.
setTimeout is synchronous in nature. Its callback get registered by event loop in timer phase which will be executed an asynchronous manner.
A callback function is passed as an argument to another function whereas Promise is something that is achieved or completed in the future. In JavaScript, a promise is an object and we use the promise constructor to initialize a promise.
Await eliminates the use of callbacks in . then() and . catch(). In using async and await, async is prepended when returning a promise, await is prepended when calling a promise.
There are two different queues involved here: a Task queue and a Microtask queue.
Callback functions scheduled using setTimeout
are added in the task queue whereas the callbacks scheduled using promises are added in the microtask queue or a job queue.
A microtask queue is processed:
Also note that if a microtask in a microtask queue queues another microtask, that will also be processed before processing anything in the task queue. In other words, microtask queue will be processed until its empty before processing the next task in the task queue.
The following code snippet shows an example:
setTimeout(() => console.log('hello'), 0);
Promise.resolve('first microtask')
.then(res => {
console.log(res);
return 'second microtask';
})
.then(console.log);
In your code, callback function of setTimeout
is added to the task queue and the Promise.resolve
queues a micro-task in a microtask queue. This queue is processed at the end of the script execution. That is why "success" is logged before "hello".
The following image shows a step-by-step execution of your code:
Resources for further reading:
Tasks, microtasks, queues and schedules
JavaScript job queue and microtasks
There are 2 separate queues for handling of the callbacks. A macro and a micro queue. setTimeout
enqueues an item in the macro queue, while promise resolution - to the micro queue. The currently executing macro task(the main script itself in this case) is executed synchronously, line by line until it is finished. The moment it is finished, the loop executes everything queued in the microtask queue before continuing with the next item from the macro queue(which in your case is the console.log("hello")
queued from the setTimeout
).
Basically, the flow looks like this:
MacrotaskQueue: [], MicrotaskQueue: [].
setTimeout(() => console.log("hello"), 0);
is encountered which leads to pushing a new item in the macrotask queue.MacrotaskQueue: [console.log("hello")
], MicrotaskQueue: [].
Promise.resolve('Success!').then(console.log)
is read. Promise resolves to Success!
immediately and console.log
callback gets enqueued to the microtask queue.MacrotaskQueue: [console.log("hello")
], MicrotaskQueue: [console.log('Success!')
].
console.log('Success!')
is pulled from the microtask queue and executed.MacrotaskQueue: [console.log("hello")
], MicrotaskQueue: [].
console.log("hello")
.MacrotaskQueue: [], MicrotaskQueue: [].
console.log("hello")
, it once again checks if there is anything in the microtask queue. It is empty, so it checks the macrotask queue. It is empty as well so everything queued is executed and the script finishes.This is a simplified explanation, though, as it can get trickier. The microtask queue normally handles mainly promise callbacks, but you can enqueue code on it yourself. The newly added items in the microtask queue will still be executed before the next macrotask item. Also, microtasks can enqueue other microtasks, which can lead to an endless loop of processing microtasks.
Some useful reference resources:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With