首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >setTimeout / Promise.resolve:宏任务与微任务

setTimeout / Promise.resolve:宏任务与微任务
EN

Stack Overflow用户
提问于 2018-08-10 20:51:09
回答 3查看 2.3K关注 0票数 14

我已经被介绍了一段时间微任务和宏任务的概念,从我所读到的所有内容来看,我总是认为setTimeout可以创建宏任务,而Promise.resolve() (或process.nextTick on NodeJS)可以创建微任务。

(是的,我知道像Q和Bluebird这样的不同承诺库有不同的调度器实现,但这里我指的是每个平台上的本地承诺)

考虑到这一点,我无法解释NodeJS上的以下事件序列( Chrome上的结果与NodeJS ( v8、LTS和v10)不同,并与我对这一主题的理解相匹配)。

代码语言:javascript
复制
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上的结果(这与我对微/宏任务以及Promise.resolve和setTimeout的行为的理解一致)如下:

代码语言:javascript
复制
Timeout  0
Promise 1  0
Promise 2  0
Timeout  1
Promise 1  1
Promise 2  1

在NodeJS输出上执行的相同代码:

代码语言:javascript
复制
Timeout  0
Timeout  1
Promise 1  0
Promise 2  0
Promise 1  1
Promise 2  1

我正在寻找一种在NodeJS上获得与Chrome相同的结果的方法。我也用process.nextTick而不是Promise.resolve()进行了测试,但是结果是一样的。

有人能把我引向正确的方向吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-01-25 10:06:46

NodeJs团队认为这是一个bug,更详细的信息如下:https://github.com/nodejs/node/issues/22257

同时,它已经修复并发布了Node v11的一部分。

最佳,何塞

票数 2
EN

Stack Overflow用户

发布于 2018-08-10 20:54:25

您无法控制不同的架构如何对承诺和超时进行排队。

很好的阅读:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

如果你想要同样的结果,你将不得不连锁承诺。

代码语言:javascript
复制
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'))

票数 1
EN

Stack Overflow用户

发布于 2018-08-10 22:40:04

我不是说我做对了,我写了一些临时的东西,我想让你测试以下几点:

包装器:

代码语言:javascript
复制
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;
}

使用

创建一个实例:

代码语言:javascript
复制
var  x = new order;

然后修改其馀部分:

代码语言:javascript
复制
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);
}

我明白了:

代码语言:javascript
复制
Timeout  0
Promise 1  0
Promise 2  0
Timeout  1
Promise 1  1
Promise 2  1

你甚至可以详细阐述一下:

代码语言:javascript
复制
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中,您可以得到:

代码语言:javascript
复制
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,node v6.11上测试

注意:--您不必保留对'x‘的引用,推送函数中的this引用order实例。您还可以使用Object.defineProperties来呈现getter/setter不可配置,防止意外删除instance.ignited等。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51793906

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档