为什么 Promise 比setTimeout() 快?

更新日期: 2021-01-26阅读: 1.6k标签: 定时器

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回调)的优先级更高。

原文: https://dmitripavlutin.com/



链接: https://fly63.com/article/detial/10110

js中setTimeout和setInterval的深入理解:它们之间的区别,原理,“异步“等

这篇文章将带你深入理解js中定时器是如何工作的,setTimeout和setInterval的原理是什么?

为什么尽量别用setInterval

在开发一个在线聊天工具时,经常会有过多少毫秒就重复执行一次某操作的需求。“没问题”,大家都说,“用setInterval好了。”我觉得这个点子很糟糕。

你可能不知道的setInterval的坑

之前印象中一直记得setInterval有一些坑,但是一直不是很清楚那些坑是什么。setInterval会无视代码的错误、setInterval会无视任何情况下定时执行、、setInterval不能确保每次调用都能执行

setInterval和setTimeout的区别以及setInterval越来越快问题的解决方法

setInterval()和setTimeout()方法都是js原生的定时方法,当然它们两个的作用也是不同的,并且最近在做上下滚动公告栏的时候,发现了setInterval()非常令人抓狂的问题,那就是用setInterval()做的定时滚动会随着浏览器页面切换变得无法控制!为什么会说无法控制呢

如何通过setTimeout理解JS运行机制详解

setTimeout()函数:用来指定某个函数或某段代码在多少毫秒之后执行。它返回一个整数,表示定时器timer的编号,可以用来取消该定时器。JavasScript引擎是基于事件驱动和单线程执行的,JS引擎一直等待着任务队列中任务的到来

node-schedule 全局内关闭定时器

用Cron表达式完成定时器,全局内关闭定时器需要获取到定时器的引用,scheduleJob存在第四个参数,然而readme中没有提及,可知API

js 随机点名

主要是利用定时器,点击开始IDE时候不断的执行,并同时生成随机数,利用数组的下标完成展示。主要用到的知识点:setInterval,Math.random()

js定时器setTiemout、setInterval

JS提供了一些原生方法来实现延时去执行某一段代码,下面来简单介绍一下setTiemout、setInterval、setImmediate、requestAnimationFrame。JS提供了一些原生方法来实现延时去执行某一段代码,下面来简单介绍一下。

Js定时器越走越快的问题

之前在项目中写了定时器来做循环播放,但是总是会有越走越快的问题,开始是以为前后的HTML代码拼接的有问题,时间紧急的情况下反复改了很多也没什么效果,后来发现是js定时器的问题,在这里记录一下。

JS 定时器的4种写法及介绍

JS提供了一些原生方法来实现延时去执行某一段代码,下面来简单介绍一下setTiemout、setInterval、setImmediate、requestAnimationFrame。setTimeout: 设置一个定时器,在定时器到期后执行一次函数或代码段

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!