【问题标题】:What happens first: setTimeout 0 or await Promise.resolve?首先会发生什么:setTimeout 0 或 await Promise.resolve?
【发布时间】:2026-01-09 10:15:01
【问题描述】:

我在 Node 和 Chrome 中看到了这种行为:

setTimeout(()=>{ console.log('timeout') }, 0)
Promise.resolve().then(()=>{ console.log('promise') })
console.log('sync')

// output order:
// sync
// promise
// timeout

我的问题是,这是一致的行为吗?即,根据规范,在记忆/已解决的承诺上的 thenawait 总是在 setTimeout(fn, 0) 之前触发吗?

我想在类似以下的情况下使用它,如果我在我的承诺中有记忆的结果,则返回一件事,如果没有,则返回另一件事:

// somewhere during object initialization
this.resultingPromise = expensiveAsyncFunction()

// in a method called frequently
Promise.race([
    new Promise(resolve => setTimeout(() => resolve('default'), 0)),
    this.resultingPromise
])

【问题讨论】:

  • 我会冒险说逻辑表明它会一直这样工作。我不知道这两种机制的内部工作原理,但是如果您设置一个计时器,创建一个已解决的承诺,然后输出到控制台,我希望看到您显示的内容。 console.log 立即工作,然后创建计时器并设置执行回调,并执行已解决的承诺。然后,将执行计时器回调,因为这将是下一步 - 计时器倒计时为零。这对我来说听起来很明智,我相信 JS 是明智的。
  • Jake Archibald 的这篇文章可能有助于澄清这种行为:jakearchibald.com/2015/tasks-microtasks-queues-and-schedules
  • 基于 *.com/a/36877743/5378743 总结点 2,您不能依赖订单。
  • 感谢@ArnelleBalane,现在看到您在 kirill.buga 在下面的回答中发布了大致相同的内容。我想我应该阅读微/宏任务来理解这一点

标签: javascript promise async-await


【解决方案1】:

不能保证一个会先于另一个。如果你想保证执行顺序 - 使用 Promises。

【讨论】:

    【解决方案2】:

    Promise.resolve 将安排一个微任务,而 setTimeout 安排一个宏任务。并且微任务将在运行下一个宏任务之前运行。

    关于事件循环的更多信息:https://www.youtube.com/watch?v=8aGhZQkoFbQ

    有关事件循环的更多技术细节:https://www.youtube.com/watch?v=cCOL7MC4Pl0

    【讨论】:

    • 这有点启发性,将查看视频。发现这个答案*.com/a/25933985/1555158 暗示这个微/宏任务的概念可能在 WHATWG 标准中。 WHATWG 标准是否也是 es6 等的一部分?还是我弄错了,这家伙只指 WHATWG 指出 task queue 在该标准中
    • 好的。会接受这个答案。从上面的@ArnelleBalane 链接 (jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/…) 看来,ECMAScript 定义了“作业”的概念,而不是明确说明什么是微任务和宏任务。因此,即使实现具有这种一致的行为,我也找不到任何说明它必须始终具有上述执行顺序
    【解决方案3】:

    所以你有 2 个异步等待状态,但请注意其中一个是恒定的,一个是变化的(变量)。超时设置在一个 XML 变量中,而承诺可能会永远持续下去。如果我很好地理解了你的问题,当你依赖的东西太长而太短时,除非你在其中一个上应用了一个常量,比如超时,那么最终可能会意外地运行更短(!)做好准备为此,而是出于代码安全原因而不是性能原因使用单片结构。

    【讨论】:

    • 对不起,我在那里看到了我的错误。编辑问题以在 setTimeout 中运行函数
    【解决方案4】:

    据我了解,Promise 在调用堆栈中的优先级高于setTimeout,当然同步代码块将首先被执行。在这种情况下,是的,上面观察到的行为(按照同步代码块、promise.resolve 和 setTimeout 0 的顺序)应该是一致的。

    【讨论】: