面试官:为什么 Promise 比setTimeout() 快?
本文已经过原作者 devinduct 授权翻译。
1.实验
我们来做个实验。哪个执行得更快:立即解决的 Promise 还是立即setTimeout(也就是0毫秒的setTimeout)?
- Promise.resolve(1).then(function resolve() {
- console.log('Resolved!');
- });
- setTimeout(function timeout() {
- console.log('Timed out!');
- }, 0);
- // 'Resolved!'
- // 'Timed out!'
promise.resolve(1)是一个静态函数,它返回一个立即解析的promise。setTimeout(callback, 0)以0毫秒的延迟执行回调函数。
我们可以看到先打印'Resolved!',再打印Timeout completed!,立即解决的 promise 比立即setTimeout更快。
是因为Promise.resolve(true).then(...)在setTimeout(..., 0)之前被调用了,所以 Promise 过程会更快吗?公平的问题。
所以,我们稍微更改一下实验条件,然后先调用setTimeout(..., 0):
- setTimeout(function timeout() {
- console.log('Timed out!');
- }, 0);
- Promise.resolve(1).then(function resolve() {
- console.log('Resolved!');
- });
- // 'Resolved!'
- // 'Timed out!'
setTimeout(..., 0)在Promise.resolve(true).then(...)之前被调用。但,还是先打印Resolved!在打印'Timed out!'。
这是为啥呢?
2.事件循环
与异步 JS 相关的问题可以通过研究事件循环来回答。我们回顾一下异步 JS 工作方式的主要组成部分。
调用堆栈是一个LIFO(后进先出)结构,它存储在代码执行期间创建的执行上下文。简单地说,调用堆栈执行这些函数。
Web api是异步操作(fetch 请求、promise、计时器)及其回调等待完成的地方。
**task queue (任务队列)是一个FIFO(先进先出)**结构,它保存准备执行的异步操作的回调。例如,超时的setTimeout()的回调函数或准备执行的单击按钮事件处理程序都在任务队列中排队。
**job queue (作业队列)**是一个FIFO(先入先出)结构,它保存准备执行的promise 的回调。例如,已完成的承诺的resolve或reject回调被排在作业队列中。
最后,事件循环永久监听调用堆栈是否为空。如果调用堆栈为空,则事件循环查看作业队列或任务队列,并将准备执行的任何回调分派到调用堆栈中。
3.作业队列与任务队列
我们从事件循环的角度来看这个实验,我将对代码执行进行一步一步的分析。
A)调用堆栈执行setTimeout(..., 0)并计划一个计时器, timeout()回调存储在Web API中:
B)调用堆栈执行 Promise.resolve(true).then(resolve)并安排一个 promise 解决方案。resolved()回调存储在Web API中:
C)promise 立即被解析,同时计时器也立即执行。这样,定时器回调timeout()进入任务队列,promise回调resolve()进入作业队列
D)现在是有趣的部分:作业队列(微任务)优先级高于任务队列(宏任务)。事件循环从作业队列中取出promise回调resolve()并将其放入调用堆栈中。然后,调用堆栈执行promise回调resolve():
E)最后,事件循环将计时器回调timeout()从任务队列中出队到调用堆栈中。然后,调用堆栈执行计时器回调timeout():
调用堆栈为空,已完成脚本的执行。
总结
为什么立即解决的 promise 比立即执行定时器处理得更快?
由于事件循环优先级的存在,因此与任务队列(存储超时的setTimeout()回调)相比,作业队列(用于存储已实现的Promise回调)的优先级更高。
完~ 我是小智,我要去刷碗了,我们下期见!
作者:Milos Protic 译者:前端小智 来源:devinduct原文:https://dmitripavlutin.com/javascript-promises-settimeout/
本文转载自微信公众号「 大迁世界」,可以通过以下二维码关注。转载本文请联系 大迁世界公众号。
相关文章
- 图像处理工具Python扩展库,你了解吗?
- 十个常用的损失函数解释以及Python代码实现
- 30 个数据科学工作中必备的 Python 包
- 如何在 Windows 上安装 Python
- 几行 Python 代码就可以提取数百个时间序列特征
- 使用Python快速搭建接口自动化测试脚本实战总结
- 哪种编程语言最适合开发网页抓取工具?
- 不要在 Python 中使用循环,这些方法其实更棒!
- 震惊!用Python探索《红楼梦》的人物关系!
- 如何最简单、通俗地理解Python模块?
- 酷炫,Python实现交通数据可视化!
- 为什么急于寻找Python的替代者?
- 30 个数据工程必备的Python 包
- 去字节面试被面这题能答上来吗?谈谈你对时间轮的理解?
- 火山引擎在行为分析场景下的 ClickHouse JOIN 优化
- 用Python爬取了某宝1166家月饼数据进行可视化分析,终于找到最好吃的月饼~
- 在 Linux 上试试这个基于 Python 的文件管理器
- Python列表解析式到底该怎么用?
- 如何快速把你的 Python 代码变为 API
- 十个Python初学者常犯的错误