I've been introduced to the concepts of Microtasks and Macrotasks for a while now, and from everything I've read, I always thought setTimeout
to be considered to create a macrotask and Promise.resolve()
(or process.nextTick
on NodeJS) to create microtasks.
(Yes, I'm aware that different Promise libraries like Q and Bluebird have different schedulers implementations, but here I'm referring to the native Promises on each platform)
With this in mind I'm unable to explain the following sequence of events on NodeJS (results on Chrome are different from NodeJS (both v8 LTS and v10) and match with my understanding on this subject).
for (let i = 0; i < 2; i++) {
setTimeout(() => {
console.log("Timeout ", i);
Promise.resolve().then(() => {
console.log("Promise 1 ", i);
}).then(() => {
console.log("Promise 2 ", i);
});
})
}
So, the results I have on Chrome (and that are consistent with my understanding of Micro/Macro tasks and how Promise.resolve and setTimeout behave) are:
Timeout 0
Promise 1 0
Promise 2 0
Timeout 1
Promise 1 1
Promise 2 1
The same code executed on NodeJS outputs:
Timeout 0
Timeout 1
Promise 1 0
Promise 2 0
Promise 1 1
Promise 2 1
I'm looking for a way to have the same results on NodeJS that I have on Chrome. I've also tested with process.nextTick
instead of Promise.resolve()
but the results are the same.
Can anyone point me into the right direction?
The certain way, is to look up the spec. For instance, step 14 of setTimeout queues a task, whereas step 5 of queuing a mutation record queues a microtask. As mentioned, in ECMAScript land, they call microtasks "jobs".
Macro tasks include keyboard events, mouse events, timer events (setTimeout) , network events, Html parsing, changing Urletc. A macro task represents some discrete and independent work. micro task queue has higher priority so macro task will wait for all the micro tasks are executed first.
In the context of native promises, a promise callback is considered as a microtask and queued in a microtask queue which will be processed right after the next tick queue. Consider the following example. In the above example, the following actions will happen.
Macro-tasks within an event loop: Macro-task represents some discrete and independent work. These are always the execution of the JavaScript code and micro-task queue is empty. Macro-task queue is often considered the same as the task queue or the event queue.
This was recognized by the NodeJs team as a bug, more details here: https://github.com/nodejs/node/issues/22257
Meantime it was already fixed and released has part of Node v11.
Best, José
You can't control how different architectures queue the promises and timeouts.
Excellent Read Here: https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
If you want the same results you are going to have to chain promises.
let chain = Promise.resolve(null)
for (let i = 0; i < 2; i++) {
console.log("Chaining ", i);
chain = chain.then(() => Promise.resolve()
.then(() => {
setTimeout(() => {
console.log("Timeout ", i);
Promise.resolve()
.then(() => {
console.log("Promise 1 ", i);
})
.then(() => {
console.log("Promise 2 ", i);
})
}, 0)
}))
}
chain.then(() => console.log('done'))
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