簡體   English   中英

setTimeout / Promise.resolve:Macrotask vs Microtask

[英]setTimeout / Promise.resolve: Macrotask vs Microtask

我已經介紹了Microtasks和Macrotasks的概念已經有一段時間了,從我讀過的所有內容來看,我一直認為setTimeout被認為是創建一個Promise.resolve()Promise.resolve() (或Promise.resolve() process.nextTick )創建微任務。

(是的,我知道像Q和Bluebird這樣的不同Promise庫有不同的調度程序實現,但這里我指的是每個平台上的本機Promises)

考慮到這一點,我無法解釋NodeJS上的以下事件序列(Chrome上的結果與NodeJS(v8 LTS和v10)不同,並且符合我對此主題的理解)。

 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); }); }) } 

因此,我在Chrome上的結果(與我對Micro / Macro任務的理解以及Promise.resolve和setTimeout的行為方式一致)是:

Timeout  0
Promise 1  0
Promise 2  0
Timeout  1
Promise 1  1
Promise 2  1

在NodeJS輸出上執行的代碼相同:

Timeout  0
Timeout  1
Promise 1  0
Promise 2  0
Promise 1  1
Promise 2  1

我正在尋找一種在Chrome上使用NodeJS獲得相同結果的方法。 我還測試了process.nextTick而不是Promise.resolve()但結果是一樣的。

有人能指出我正確的方向嗎?

您無法控制不同的體系結構如何排列承諾和超時。

優秀閱讀: https//jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

如果你想要相同的結果,你將不得不鏈接承諾。

 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')) 

這被NodeJs團隊認為是一個錯誤,更多詳情請點擊這里: https//github.com/nodejs/node/issues/22257

同時它已經修復並發布了Node v11的一部分。

最好的,何塞

我不是說我做對了,我寫了一些adhoc,我希望你測試下面的內容:

包裝器:

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;
}

使用:

創建一個實例:

var  x = new order;

然后稍微修改其余部分:

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);
}

我明白了:

Timeout  0
Promise 1  0
Promise 2  0
Timeout  1
Promise 1  1
Promise 2  1

你甚至可以詳細說明一下:

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);
}

在節點v6中,您將獲得:

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

你會在我的節點版本中嘗試這個嗎? 在我的節點(6.11,我知道它的舊)它的工作原理。

測試了chrome,firefox,節點v6.11

注意:您不必保持對'x'的引用, this在推送的函數中引用了order實例。 您還可以使用Object.defineProperties來呈現Object.defineProperties配置的getter / setter,以防止意外刪除instance.ignited等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM