Promise 与 setTimeout

IT技术 javascript asynchronous
2021-01-31 14:23:09

我在以下代码中观察到了这一点:

setTimeout(function(){console.log('setTimeout')});
Promise.resolve(1).then(function(){console.log('promise resolve')})

无论我执行多少次,promise 回调总是在 setTimeout 之前记录。

我的理解是,这两个回调都计划在下一个滴答声中执行,我真的不明白发生了什么使得Promise始终优先于超时。

6个回答

Promise.resolve 调度一个微任务, setTimeout 调度一个宏任务。并且在运行下一个宏任务之前执行微任务。

另外值得一提的是,微任务的来源可能只有两件事:MutationObserver 和 Promises。
2021-03-27 14:23:09
这是最接近的答案。我会添加链接到任务/微任务的深入解释。jakearchibald.com/2015/tasks-microtasks-queues-and-schedules
2021-04-02 14:23:09

简短回答Promise比事件循环堆栈中的 setTimeout 回调函数具有更好的优先级(或我如何理解它)。

长答案看这个视频。很有帮助。希望这可以帮助。

https://www.youtube.com/watch?v=8aGhZQkoFbQ

感谢@MickJuice 为事件循环提供新的和更新的视频。

https://www.youtube.com/watch?v=cCOL7MC4Pl0

在另一个答案的评论中提到的一篇好文章:jakarchibald.com/2015/tasks-microtasks-queues-and-schedules
2021-03-22 14:23:09
这是一个很棒的视频。那么这是否可以帮助您了解任务和事件的优先级:youtube.com/watch?v=cCOL7MC4Pl0
2021-04-01 14:23:09

setTimeout()拥有4ms的最小延迟,所以即使你没有指定代码中的延迟超时仍将至少4毫秒延迟。您的Promise.then()在此期间被调用。

嗯...好吧,但实际上 4ms 的最小值确实适用,因此对于宏与微任务先验问题中的示例适用。如果我们要想象与实际实现的行为不同的行为,那么即使 Promise 的优先级低于超时,示例中的 Promise 仍会首先记录,因为最小超时时间为 4 毫秒。尽管如此,回到现实世界中,知道微任务概念存在于 JS 中还是很有用的,所以感谢您提到它。
2021-03-15 14:23:09
即使没有 4ms 的节流优化,promise 也会更快。因为setTimeout创建任务并Promise创建微任务(作业)。这才是真正的原因。
2021-03-24 14:23:09
meantime ...更准确地说:在下一个滴答声中
2021-04-07 14:23:09

超时Promise都用于以异步方式执行代码,但具有不同的特征和目的:

setTimeout - 按特定的持续时间延迟函数的执行。- 不阻塞其余的代码执行(异步行为) - 他们创建 Macrotask(浏览器内部操作)

Promises - 它们是允许异步执行代码的包装器(例如:ajax 调用)。(不依赖于特定的持续时间) - 它们对于链接不同的异步调用特别有用。- 在使用 await 运算符的情况下,不会阻止其余的代码执行(异步行为)。- 他们创建微任务(浏览器内部操作),其优先于宏任务

推荐

  • 当您希望将函数执行延迟某个特定的持续时间而不阻止进程中的其余代码执行时,请使用setTimeout

  • 使用Promises:当你想执行一些异步代码并避免“回调地狱”时(是的,因为你可以在没有 Promises 的情况下进行异步 ajax 调用,但语法不太清晰,更容易出错)

值得一提的是,Promise executor——传递给的函数new Promise(...)——是同步运行的。
2021-03-20 14:23:09

这与Web Spec 中定义事件循环有关浏览器有多个任务队列用于多种类型的任务(例如通过创建的定时器任务),以及一个微任务队列(Promise 结算被推送到的地方)。每当浏览器完成执行任务时,它会清空微任务队列并执行其中的所有任务,然后再继续执行另一个任务队列中的任务。setTimeout

因此在代码执行后(这是一个任务),Promise 结算在微任务队列内,而定时器任务可能已经在任务队列内¹。微任务队列被清空,Promise 被解析。然后在计时器任务运行的某个时候。

¹ 浏览器可能会选择稍微增加超时时间,他们确实这样做了。在大多数浏览器中,0 毫秒后永远不会运行超时。