浅谈对于“不用setInterval,用setTimeout”的理解


Posted in Javascript onAugust 28, 2019

JavaScript高级程序设计(第三版)(以下简称红宝书)22.3高级定时器中详细介绍了定时器setTimeout和setInterval,看完书后,深入理解了二者的区别,结合前辈们给我的建议“用setTimeout,不要用setInterval”,写下此文,分析这个建议的合理性。
这两个家伙看上去长得差不多,func是要执行的函数,interval是时间间隔。

setTimeout(func,interval)
setInterval(func,interval)

关于时间间隔,红宝书中这么说:

设定一个 150ms 后执行的定时器不代表到了 150ms 代码就立刻执行,它表示代码会在 150ms 后被加入到队列中。如果在这个时间点上,队列中没有其他东西,那么这段代码就会被执行。

对于这个时间间隔的理解非常重要!步入正题,为何不用setInterval,因为它可能会带来两个问题:

  • “丢帧”现象
  • 不同定时器的代码的执行间隔比预期小

一图胜千言,如下图所示,让我们跟着时间线看看这样的问题怎么发生的。假定一个场景,在click事件中设置了setInterval(func,500),假设click事件和定时器内函数的执行时间都是1s,为了方便陈述,我把不同时间触发的func取了不同的名字,实际上接下来的func1=func2=func3=func。在0s处触发click事件,click事件执行,在0.2s处触发定时器,0.7s处第一个函数func1加入到事件队列,但由于JS引擎是单线程的,click事件还在执行,所以func1等待着,等到1s处,click事件执行完毕,fun1才开始执行。按照定时器的时间间隔,1.2s处第二个函数func2加入到事件队列,但此时fun1正在执行,所以func2只能等待。0.5s后,也就是1.7s处,第三个函数func理应加入事件队列,但是JS引擎做了一个事情:

当使用 set Interval()时,仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中。

在1.7s处,func1在执行,func2在队列里等待执行,func2就是该定时器的代码实例,按照JS引擎的处理,func3不会加入到事件队列里,更别说执行了,这就导致出现了“丢帧”现象。而在图中也可以注意到,func1执行完毕,线程空闲了,func2就可以执行了,这就使得func1和func2之间的执行没有时间间隔,这跟我们所预期的500ms产生一次结果是不同的。

浅谈对于“不用setInterval,用setTimeout”的理解

而如果使用链式setTimeout调用,每次函数执行的时候都会创建一个新的定时器。第二个setTimeout()调用使用了 arguments.callee 来获取对当前执行的函数的引用,并为其设置另外一个定时器。这样做的好处是,在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。而且,它可以保证在下一次定时器代码执行之前,至少要等待指定的间隔,避免了连续的运行。代码如下所示

setTimeout(function(){
  //do something
  setTimeout(arguments.callee,interval);
},interval)

用setTimeout方法的话,上面假设的场景就发生了改变,如下图所示,在0s处触发click事件,click事件执行,在0.2s处触发定时器,0.7s处第一个函数func1加入到事件队列,click事件执行了1s,在1s处func1执行,2s处func1执行结束,第二个setTimeout定时器才被触发,0.5s后将函数func2加入队列,此时队列为空,func2开始执行,3.5s处func2执行结束,又一个setTimeout定时器被触发,0.5s后将函数func3加入队列,此时队列为空,func3开始执行。。。

浅谈对于“不用setInterval,用setTimeout”的理解

通过上面这个场景,我们能知道当需要用定时器来设置一个操作重复执行,并且这个操作需要执行一定的时间,记得用setTimeout,不用setInterval!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
判断访客终端类型集锦
Jun 05 Javascript
IE6-IE9使用JSON、table.innerHTML所引发的问题
Dec 22 Javascript
jQuery checkbox选中问题之prop与attr注意点分析
Nov 15 Javascript
浅谈jQuery before和insertBefore的区别
Dec 04 Javascript
AngularJS 使用ng-repeat报错 [ngRepeat:dupes]
Jan 19 Javascript
基于JS实现bookstore静态页面的实例代码
Feb 22 Javascript
Node.js 中exports 和 module.exports 的区别
Mar 14 Javascript
微信小程序拼接图片链接无底洞深入探究
Sep 03 Javascript
浅谈vue 多个变量同时赋相同值互相影响
Aug 05 Javascript
基于Ionic3实现选项卡切换并重新加载echarts
Sep 24 Javascript
JavaScript 生成唯一ID的几种方式
Feb 19 Javascript
交互式可视化js库gojs使用介绍及技巧
Feb 18 Javascript
Vue的编码技巧与规范使用详解
Aug 28 #Javascript
JS开发自己的类库实例分析
Aug 28 #Javascript
详解Vue 换肤方案验证
Aug 28 #Javascript
Vue项目实现换肤功能的一种方案分析
Aug 28 #Javascript
js遍历详解(forEach, map, for, for...in, for...of)
Aug 28 #Javascript
Angular6使用forRoot() 注册单一实例服务问题
Aug 27 #Javascript
jQuery - AJAX load() 实例用法详解
Aug 27 #jQuery
You might like
PHP中将字符串转化为整数(int) intval() printf() 性能测试
2020/03/20 PHP
PHP+FastCGI+Nginx配置PHP运行环境
2014/08/07 PHP
JS字符串函数扩展代码
2011/09/13 Javascript
Javascript在IE和FireFox中的不同表现简析
2012/12/03 Javascript
JavaScript中字面量与函数的基本使用知识
2015/10/20 Javascript
jQuery simplePage+AJAX plus分页插件用法实例
2016/02/17 Javascript
很酷的星级评分系统原生JS实现
2016/08/25 Javascript
bootstrap表格分页实例讲解
2016/12/30 Javascript
Vue.js实现多条件筛选、搜索、排序及分页的表格功能
2020/11/24 Javascript
angular实现页面打印局部功能的思考与方法
2018/04/13 Javascript
Vue实现移动端左右滑动效果的方法
2018/11/27 Javascript
Vue中通过Vue.extend动态创建实例的方法
2019/08/13 Javascript
vue实现输入框的模糊查询的示例代码(节流函数的应用场景)
2019/09/01 Javascript
vue任意关系组件通信与跨组件监听状态vue-communication
2020/10/18 Javascript
NodeJS模块Buffer原理及使用方法解析
2020/11/11 NodeJs
[54:26]完美世界DOTA2联赛PWL S3 Forest vs Rebirth 第一场 12.10
2020/12/12 DOTA
深入理解Python中range和xrange的区别
2017/11/26 Python
python实现关键词提取的示例讲解
2018/04/28 Python
Django教程笔记之中间件middleware详解
2018/08/01 Python
对Pycharm创建py文件时自定义头部模板的方法详解
2019/02/12 Python
使用python实现mqtt的发布和订阅
2019/05/05 Python
Python交互式图形编程的实现
2019/07/25 Python
Python操作Sonqube API获取检测结果并打印过程解析
2019/11/27 Python
Glamest意大利:女性在线奢侈品零售店
2019/04/28 全球购物
应届毕业生的自我鉴定
2013/11/13 职场文书
校园歌咏比赛主持词
2014/03/18 职场文书
生产助理岗位职责
2014/06/18 职场文书
计划生育宣传标语
2014/06/21 职场文书
承诺书范本
2015/01/21 职场文书
法人身份证明书
2015/06/18 职场文书
乡镇司法所2015年度工作总结
2015/10/14 职场文书
2016年国陪研修感言
2015/11/18 职场文书
学会Python数据可视化必须尝试这7个库
2021/06/16 Python
python opencv将多个图放在一个窗口的实例详解
2022/02/28 Python
基于Python实现流星雨效果的绘制
2022/03/18 Python
instantclient客户端 连接oracle数据库
2022/04/26 Oracle