admin管理员组文章数量:1327675
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);
});
})
}
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?
Share Improve this question edited Aug 10, 2018 at 21:24 jpsfs asked Aug 10, 2018 at 20:51 jpsfsjpsfs 7082 gold badges7 silver badges24 bronze badges 13- FWIW: When I run the example in Node a few times I see both results happen a few times. It doesn't seem to be pletely consistent. – Alexander O'Mara Commented Aug 10, 2018 at 20:55
- Thanks for you ment. You are correct, I had not realized that yet. That makes this even more hard to understand actually :/ – jpsfs Commented Aug 10, 2018 at 20:58
- Try a timeout greater than 0? – Bergi Commented Aug 10, 2018 at 20:58
- Are you just trying to get a better understanding or do you have an actual problem in real code? – Bergi Commented Aug 10, 2018 at 20:59
- 1 Basically what you are asking for is async code to be forced to run in order, pretty simple to do this using async / await. – James Commented Aug 10, 2018 at 23:15
3 Answers
Reset to default 2This was recognized by the NodeJs team as a bug, more details here: https://github./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./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'))
I am not saying I got it right, I wrote something adhoc and I'd like you to test the below:
the wrapper:
function order(){
this.tasks = [];
this.done = false;
this.currentIndex = 0;
this.ignited = false;
}
order.prototype.push = function(f){
var that = this,
args = Array.prototype.slice.call(arguments).slice(1);
if(this._currentCaller){
this.tasks.splice(
this.tasks.indexOf(this._currentCaller) + 1 + (this.currentIndex++),
0,
function(){that._currentCaller = f; f.apply(this,args);}
);
} else {
this.tasks.push(function(){that._currentCaller = f; f.apply(this,args);});
}
!this.ignited && (this.ignited = true) && this.ignite();
return this;
}
order.prototype.ignite = function(){
var that = this;
setTimeout(function(){
if(that.tasks.length){
that.tasks[0]();
that.tasks.shift();
that.repeat(function(){that.reset(); that.ignite()});
} else {
that.ignited = false;
that.reset();
}
},0);
}
order.prototype.repeat = function(f){
var that = this;
if(this.done || !this.tasks.length){
f();
} else {
setTimeout(function(){that.repeat(f);},0);
}
}
order.prototype.reset = function(){
this.currentIndex = 0;
delete this._currentCaller;
this.done = false;
}
to use:
create an instance:
var x = new order;
then modify the rest a bit:
for (let i = 0; i < 2; i++) {
x.push(function(i){
setTimeout(() => {
console.log("Timeout ", i);
x.push(function(i){
Promise.resolve().then(() => {
console.log("Promise 1 ", i);
}).then(() => {
console.log("Promise 2 ", i);
x.done = true;
})
},i);
x.done = true;
});
},i);
}
I get this:
Timeout 0
Promise 1 0
Promise 2 0
Timeout 1
Promise 1 1
Promise 2 1
You can even elaborate a bit:
for (let i = 0; i < 2; i++) {
x.push(function(i){
setTimeout(() => {
console.log("Timeout ", i);
x.push(function(i){
Promise.resolve().then(() => {
console.log("Promise 1 ", i);
}).then(() => {
console.log("Promise 2 ", i);
x.done = true;
})
},i)
.push(function(i){
Promise.resolve().then(() => {
console.log("Promise 1 ", i);
}).then(() => {
console.log("Promise 2 ", i);
x.done = true;
})
},i+0.5)
.push(function(i){
Promise.resolve().then(() => {
console.log("Promise 1 ", i);
}).then(() => {
console.log("Promise 2 ", i);
x.done = true;
})
},i+0.75);
x.done = true;
});
},i);
}
In node v6, you get:
Timeout 0
Promise 1 0
Promise 2 0
Promise 1 0.5
Promise 2 0.5
Promise 1 0.75
Promise 2 0.75
Timeout 1
Promise 1 1
Promise 2 1
Promise 1 1.5
Promise 2 1.5
Promise 1 1.75
Promise 2 1.75
Would you try this in your node version for me? In my node (6.11, I know its old) it works.
Tested on chrome, firefox, node v6.11
Note: you don't have to keep reference to 'x', this
within the pushed functions refer to the order
instance. You can also use Object.defineProperties
to render getters/setters unconfigurable, to prevent accidental deletion of instance.ignited
etc.
本文标签: javascriptsetTimeoutPromiseresolve Macrotask vs MicrotaskStack Overflow
版权声明:本文标题:javascript - setTimeoutPromise.resolve: Macrotask vs Microtask - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742224418a2435868.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论