使用setTimeout()代替setInterval()
背景:
在JavaScript中,有两种定时器:setTimeout()和setInterval();setTimeout()只执行一次定时操作,setInterval()执行无限次定时操作;但是大多数的观点均是尽可能多使用setTimeout(),多次定数操作也是十使用setTimeout()代替setInterval()。
定时器的运行原理:
要了解这样做原因首先要知道定时器的工作方式:JavaScript语言是单线程语言,它有一个叫做执行队列的东西来决定代码的执行顺序,而定时器的作用是:在特定的时间后将代码插入到执行队列。
这里要特别理解:定时器setTimeout(function, Interval)这里的Interval是指当Interval个单位时间过去之后将代码function插入到执行队列中,而不是过去Interval个单位时间之后执行function代码。也就说明代码的执行的时间将大于等于Interval。
setInterval()定时器存在的问题:
1. 定时器中的某些间隔会被跳过;
2. 定时器之间的代码间隔可能会比预期小;

对于存在问题1的理解:如上图所示:这个例子中的第 1 个定时器是在 205ms 处添加到队列中的(即使任务队列为空,0ms实际上是达不到的,因此至少为5ms),但是直到过了 300ms 处才能够执行。当执行这个定时器代码时,在 405ms 处又给任务队列添加了另外一个副本。在下一个间隔,即 605ms 处,第一个定时器代码仍在运行,同时在任务队列中已经有了一个定时器代码的实例。结果是,在这个时间点上的定时器代码不会被添加到队列中。结果在 5ms 处添加的定时器代码结束之后,405ms 处添加的定时器代码就立刻执行。
对于存在问题2的理解:某个 onclick 事件处理程序使用 setInterval() 设置了一个 200ms 间隔的重复定时器。如果事件处理程序花了 300ms 的时间完成,同时定时器代码也花了差不多的时间,就会同时出现跳过间隔且连续运行定时器代码的情况。
个人疑惑之处:
首先是对于setInterval的问题1,自己尝试了写演示代码,发现最后都不能得到自己想要的输出结果(最大可能是自己理解得不够深),因为不知道用什么方法捕获那个被跳过的代码。最后我发现了一个特点:其实定时器忽略某个插入代码,好像是无关紧要的,因为一般的我们插入的函数中都包含这一些操作函数,这些操作函数如果没有执行,那么参数就不会发生变化,那么就不会影响最后的输出结果。
对于setInterval的问题2,自己写出了演示代码, 演示代码如下:
 const log = console.log.bind(console)
 const timeDelay = (delayTime) => {
     let time = new Date()
     // console.log(time.getTime())
     while(true) {
         var t1 = new Date()
         if ((t1.getTime() - time.getTime()) >= Number(delayTime)) {
             // console.log(t1.getTime())
             break
         }
     }
 }
 const func = () => {
     console.log("开始执行时间:" + new Date().toLocaleTimeString())
     timeDelay(6000)
     console.log("结束执行时间:" + new Date().toLocaleTimeString())
 }
 // console.log(new Date().toLocaleTimeString())
 // setInterval(func, 2000)
 // 开始执行时间:19:42:36
 // 结束执行时间:19:42:42
 // 开始执行时间:19:42:42 // 上一次的结束到下一次的开始, 间隔为0
 // 结束执行时间:19:42:48
 // 开始执行时间:19:42:50 // 上一次的结束到下一次的开始, 间隔为2(不太理解这里时间间隔为什么为2s)
 // 结束执行时间:19:42:56
 // 开始执行时间:19:42:56 // 上一次的结束到下一次的开始, 间隔为0
 setTimeout(function () {
     func()
     setTimeout(arguments.callee, 2000)
 },2000)
 // 开始执行时间:19:44:45
 // 结束执行时间:19:44:51
 // 开始执行时间:19:44:53 // 上一次的结束到下一次的开始, 间隔为2
 // 结束执行时间:19:44:59
 // 开始执行时间:19:45:01 // 上一次的结束到下一次的开始, 间隔为2
 // 结束执行时间:19:45:07
 // 开始执行时间:19:45:09 // 上一次的结束到下一次的开始, 间隔为2
使用setTimeout代替setInterval的方法:
 let n = setTimeout(function () {
     // 判断是否将操作代码插入执行队列
     if (boolean) {
         // 需要插入执行队列的代码
         function()
     }
     // 判断是否进行定时器的递归
     if () {
         n = setTimeout(arguments.callee, interval)
     }
 }, interval)
最好假如判断条件,这样方便控制整个定时器的循环
引用:
1. JavaScript定时器及相关面试题:https://www.cnblogs.com/unclekeith/p/6443115.html
使用setTimeout()代替setInterval()的更多相关文章
- 深入理解定时器系列第一篇——理解setTimeout和setInterval
		
× 目录 [1]setTimeout [2]setInterval [3]运行机制[4]作用[5]应用 前面的话 很长时间以来,定时器一直是javascript动画的核心技术.但是,关于定时器,人们通 ...
 - 前端开发:setTimeout与setInterval 定时器与异步循环数组
		
前端开发:setTimeout与setInterval 定时器与异步循环数组 前言: 开通博客园三个月以来,随笔记录了工作中遇到的大大小小的难题,也看过无数篇令人启发的文章,我觉得这样的环境是极好的, ...
 - setTimeout和setInterval从入门到精通
		
我们在日常web前端开发中,经常需要用到定时器方法. 前端中的定时器方法是浏览器提供的,并不是ECMAScript规范中的.是window对象的方法. 浏览器中的定时器有两种, 一种是每间隔一定时间执 ...
 - setTimeout和setInterval定时器使用详解测试
		
var len=4; while(len--){ var time=setTimeout(function(){ console.log(len); },0); console.log(time); ...
 - setTimeout,setInterval原理
		
function a() { setTimeout(function(){alert(1)},0); alert(2); } a(); 和其他的编程语言一样,Javascript中的函数调用也是通过堆 ...
 - Javascript的setTimeOut()和setInterval()的定时器用法
		
Javascript用来处理延时和定时任务的setTimeOut和setInterval函数应用非常广泛,它们都用来处理延时和定时任务,比如打开网页一段时间后弹出一个登录框,页面每隔一段时间发送异步请 ...
 - setTimeout和setInterval的注意事项
		
精准问题 setTimeout的问题在于它并不是精准的,例如使用setTimeout设定一个任务在10ms后执行,但是在9ms后,有一个任务占用了5ms的cpu时间片,再次轮到定时器执行时,时间已经过 ...
 - setTimeout和setInterval的区别以及如何写出效率高的倒计时
		
1.setTimeout和setInterval都属于js中的定时器,可以规定延迟时间再执行某个操作,不同的是setTimeout在规定时间后执行完某个操作就停止了,而setInterval则可以一直 ...
 - setTimeout()与setInterval()
		
一.setTimeout与setInterval的用法(http://www.css88.com/archives/5804) setTimeout是超时调用,javascript是一个单线程的解析器 ...
 - setTimeout 和 setInterval
		
设置定时器,在一段时间之后执行指定的代码,setTimeout与setInterval的区别在于setTimeout函数指定的代码仅执行一次 方法一: window.setTimeout(" ...
 
随机推荐
- 深入理解Mybatis插件
			
Mybatis插件实现原理 本文如有任何纰漏.错误,请不吝指出,谢谢! 首先,我并没有使用过 Mybatis的插件,但是这个和我写这篇文章并不冲突,估计能真正使用到插件的人也比较少,写这篇文章的目的主 ...
 - Ubuntu 18.04 新系统 允许root远程登录
			
1. 查看ssh服务器是否安装并启动 #sudo ps -e | grep ssh 1. 安装ssh服务器 #sudo apt-get install openssh-server 2. 配置sshd ...
 - Java 多线程启动为什么调用 start() 方法而不是 run() 方法?
			
多线程在工作中多多少少会用到,我们知道启动多线程调用的是 start() 方法,而不是 run() 方法,你知道原因吗? 在探讨这个问题之前,我们先来了解一些多线程的基础知识~ 线程的状态 Java ...
 - SpringData:关联查询
			
一.查询方式 1.导航式查询 使用“对象.属性” 进行查询:对于多的查询, 默认就是延迟加载,添加注解@Transactional 在OneToMany 注解中需要添加属性 fetch:值:F ...
 - 2018-08-26 jQuery与javaScript的区别及核心方法
			
1.jq对象就是js new Object 生成的普通对象. 2.jq对象与js对象,他们的方法不能共用! 3.jq对象与js对象的相互转化: js对象转jq对象 -> $(js_obj);// ...
 - python--封装Redis
			
Redis封装 import redis class MyRedis(): def __init__(self,ip,password,port=6379,db=1):#构造函数 ...
 - webpack从零的实践(新手良药)
			
1. 什么是webpack? 本质上,webpack是一个现代javascript应用程序的静态模块打包器.webpack处理应用程序时,它会递归地构建一个依赖关系图(dependency graph ...
 - Spring Boot 使用 JSR303 实现参数验证
			
简介 JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation. 在任何时候,当你要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情.应用程序必须通过 ...
 - MySQL++:liunx 安装 MySQL
			
第一步: 1):下载mysql安装包:这里选择下载版本 5.6.33,通用版,linux下64位 http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql- ...
 - flask之CBV模式
			
flask_cbv.py ''' flask中的CBV模式: (1)导入views模块: from flask import views (2)定义类,继承views.MethodView类: cla ...