【问题标题】:Why is a promise resolved before a setTimeout [duplicate]为什么在 setTimeout 之前解决承诺 [重复]
【发布时间】:2020-10-25 22:53:52
【问题描述】:

我有以下说明

console.log(1)
setTimeout(() => {
  console.log(3)
});
Promise.resolve().then(() => console.log(4))
console.log(7)

输出是:

1
7
4
3

执行顺序如下:

  • 控制台被执行
  • 承诺已解决
  • settimeout 已执行

为什么承诺在 setTimeout 之前解决?两者都由回调处理,对吧?

【问题讨论】:

  • Promise 优先于计时器。因此,如果两者同时在事件队列中,那么 Promise 将首先得到服务。

标签: javascript node.js promise settimeout


【解决方案1】:

Promise .then() 回调将在代码块完成后立即调用。计时器将获得大约 15 或 16 毫秒的默认最短时间,因此它肯定会在那之后发生。

edit — 显然在这个疯狂的现代世界中,最短时间大约是 4 毫秒,而不是 15 或 16 毫秒。

【讨论】:

  • 我很欣赏这个答案,我理解执行顺序,但为什么它肯定会在那之后发生?
  • 不完全... setTimeout 是瞬时的,除非它被多次调用。在这种情况下,它至少有 4 毫秒。见this
  • @D.Pardal 呃,不,还有几毫秒的最小延迟。最重要的是,有单独的事件队列用于 Promise 解决和计时器之类的事情。您误读了您发布的文档。
  • 只有在安排了多个未决超时时,该限制才相关。只有一次超时没有限制:developer.mozilla.org/en-US/docs/Web/API/…
  • 作为现实检查,试试这个:console.time('timeout'); setTimeout(() => console.timeEnd('timeout'), 0); 对我来说,它记录 ~1.35ms
【解决方案2】:

有趣的问题。为了理解原因,我们需要了解 JavaScript 事件循环。

.then() 将微任务排队。一旦 JS 调用堆栈清空,微任务就会执行。

在这种情况下 (but not in all cases),setTimeout 在主任务队列中排队一个任务。任务排队等待外部事件、定时器处理程序、渲染(在浏览器中)等......如果一个任务调用 JS 代码,下一个任务将不会运行,直到与其关联的所有微任务都运行完。

这就是正在发生的事情:

  1. 任务 #1,由 Node.js 在内部排队:
    1. console.log(1) 记录 1输出为1
    2. setTimeout(() => { console.log(3) });task 排队以记录 3
    3. Promise.resolve().then(() => console.log(4))微任务 排队以记录 4
    4. console.log(7) 记录 7输出为1 7
    5. JS 堆栈清空,因为没有更多的语句。微任务开始执行。
      1. 微任务 #1-1,由.then() 排队:
        1. 记录4输出为1 7 4
  2. 任务 #2,由setTimeout() 排队:
    1. 记录3输出为1 7 4 3
    2. JS 堆栈清空,因为没有更多的语句,但是没有微任务。 最终输出:
1
7
4
3

【讨论】:

  • 所有的承诺都进入微任务队列吗?
  • 所有 .then().catch() 回调函数,异步函数中 await 之后的代码也是如此。
猜你喜欢
  • 2015-06-24
  • 1970-01-01
  • 1970-01-01
  • 2021-07-13
  • 1970-01-01
  • 2019-10-18
  • 2020-08-28
  • 1970-01-01
  • 2015-11-10
相关资源
最近更新 更多