浅谈对于“不用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 相关文章推荐
javascript去掉前后空格的实例
Nov 07 Javascript
关闭ie窗口清除Session的解决方法
Jan 10 Javascript
JavaScript将Web页面内容导出到Word及Excel的方法
Feb 13 Javascript
jQuery实现边框动态效果的实例代码
Sep 23 Javascript
微信小程序 MD5加密登录密码详解及实例代码
Jan 12 Javascript
js es6系列教程 - 基于new.target属性与es5改造es6的类语法
Sep 02 Javascript
Vue学习笔记之表单输入控件绑定
Sep 05 Javascript
vue的全局提示框组件实例代码
Feb 26 Javascript
JavaScript 2018 中即将迎来的新功能
Sep 21 Javascript
vue配置文件实现代理v2版本的方法
Jun 21 Javascript
layui关闭弹窗后刷新主页面和当前更改项的例子
Sep 06 Javascript
Vue父子传递实例讲解
Feb 14 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
linux平台编译安装PHP7并安装Redis扩展与Swoole扩展实例教程
2016/09/30 PHP
PHPExcel导出2003和2007的excel文档功能示例
2017/01/04 PHP
php实现数组中出现次数超过一半的数字的统计方法
2018/10/14 PHP
php伪静态验证码不显示的解决方案
2019/09/26 PHP
suggestion开发小结以及对键盘事件的总结(针对中文输入法状态)
2011/12/20 Javascript
Javascript全局变量var与不var的区别深入解析
2013/12/09 Javascript
jquery validate 自定义验证方法介绍 日期验证
2014/02/27 Javascript
Javascript单元测试框架QUnitjs详细介绍
2014/05/08 Javascript
javascript搜索框效果实现方法
2015/05/14 Javascript
js动态添加的DIV中的onclick事件简单实例
2016/07/25 Javascript
JavaScript中浅讲ajax图文详解
2016/11/11 Javascript
原生js实现新闻列表展开/收起全文功能
2017/01/20 Javascript
微信小程序  TLS 版本必须大于等于1.2问题解决
2017/02/22 Javascript
Node.js使用orm2进行update操作时关联字段无法修改的解决方法
2017/06/13 Javascript
最后说说Vue2 SSR 的 Cookies 问题
2018/05/25 Javascript
如何把vuejs打包出来的文件整合到springboot里
2018/07/26 Javascript
Angular刷新当前页面的实现方法
2018/11/21 Javascript
jQuery插件实现非常实用的tab栏切换功能【案例】
2019/02/18 jQuery
基于vue框架手写一个notify插件实现通知功能的方法
2019/03/31 Javascript
Python中多线程及程序锁浅析
2015/01/21 Python
举例讲解Python中metaclass元类的创建与使用
2016/06/30 Python
Pytorch入门之mnist分类实例
2018/04/14 Python
python调用OpenCV实现人脸识别功能
2018/05/25 Python
解决windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的问题
2020/05/20 Python
Python DES加密实现原理及实例解析
2020/07/17 Python
Python常用外部指令执行代码实例
2020/11/05 Python
使用Python获取爱奇艺电视剧弹幕数据的示例代码
2021/01/12 Python
H5 canvas中width、height和style的宽高区别详解
2018/11/02 HTML / CSS
一套Delphi的笔试题一
2016/02/14 面试题
光信息科学与技术专业职业生涯规划
2014/03/13 职场文书
护理专业毕业生自荐书
2014/05/24 职场文书
公司新人试用期自我评价
2014/09/17 职场文书
财务审计整改报告
2014/11/06 职场文书
Python面向对象之内置函数相关知识总结
2021/06/24 Python
JavaScript 数组去重详解
2021/09/15 Javascript
直播实况, OMG破敌三路五十分钟大战神技局摩托车
2022/04/01 DOTA