“怎么做?”;返回承诺。解决();影响JavaScript事件循环?

“怎么做?”;返回承诺。解决();影响JavaScript事件循环?,javascript,ecmascript-6,es6-promise,event-loop,Javascript,Ecmascript 6,Es6 Promise,Event Loop,我已经使用Javascript一段时间了,我了解Javascript事件循环是如何工作的。然而,我遇到了一个对我来说毫无意义的案例。 考虑下面的代码: setTimeout(()=> console.log('1')); Promise.resolve('whatever').then(()=>console.log('2')); console.log('3'); 我期望这个输出: 3 1 二, 但是,我在chrome js控制台上运行它,得到以下结果: 3 2 一, 问题:“P

我已经使用Javascript一段时间了,我了解Javascript事件循环是如何工作的。然而,我遇到了一个对我来说毫无意义的案例。 考虑下面的代码:

setTimeout(()=> console.log('1'));
Promise.resolve('whatever').then(()=>console.log('2'));
console.log('3');
我期望这个输出:

3
1
二,

但是,我在chrome js控制台上运行它,得到以下结果:

3
2
一,


问题:“Promise.resolve().then(fn)”不应该立即调用函数,或者按照“setTimeout”的工作方式将函数执行过程插入到事件循环的末尾吗?我缺少什么吗?

setTimeout的行为遵循一组细微的规则。例如,在多个浏览器上,最小超时为

您是正确的,承诺不会立即执行,而是等待干净的堆栈运行


还有一些技巧,比如添加一个标记,强制将某个对象碰撞到事件循环的顶部。请参阅polyfill for Browser

浏览器实现多个作业/任务队列:

  • 脚本队列
  • 承诺队列
  • 很可能还有一个TimerQueue(HTMLDOM任务队列)也包含HTMLDOM级别2计时器规范。这些都是在运行时填充的FIFO队列,并最终被删除。下面是您的代码示例:

    setTimeout(()=> console.log('1'));
    Promise.resolve('whatever').then(()=>console.log('2'));
    console.log('3');
    
    • 第1行推送到(可能)计时器队列(HTML DOM任务队列)
    • 第2行推到 承诺队列
    • 第3行被推到堆栈上并立即执行 (直至完成)
    一旦堆栈为空,每个队列将一直排干,直到为空。在您的示例中,Promise队列首先清空,TimerQueue最后清空

    通过稍微扩展一下您的示例,可以进一步证明这一点:


    setTimeout(()=>console.log('second from final');//console.log('2');//console.log('恰好在final之前');//console.log('1');//console.log('final');//Promise回调的一个重要行为是,它们总是以“干净的堆栈”运行。您可以将消息附加到事件循环的当前迭代中,或将一个消息前置到下一个<代码>承诺
    执行前者,设置超时执行后者。因此,您可以通过递归调用
    然后
    来阻止事件循环,但不能通过递归调用
    setTimeout
    “第1行推到ScriptQueue上”-否。
    setTimeout
    在ECMAScript中根本没有指定,并且它不使用ScriptQueue。为此,您必须查看HTML5定时器规范。@Bergi-恕我直言,作为未来执行请求的每个作业都会排队-无论该请求的来源如何。如果不是承诺,作业将在ScriptQueue中排队。是的,它们都已排队,但
    setTimeout
    甚至不创建“作业”。它创建了一个“任务”。术语“作业”仅在ECMAScript规范中使用。HTMLDOMLevel2任务/微任务和ECMAScript作业之间存在1:1的关系。这很可能是,但我仍然确定脚本和计时器(以及承诺和其他内容)有单独的队列。