说明

在开发功能“轨迹播放”时,遇到了一个情况。

原先同事已经开发了一版,这次有个新功能:点击线上任意一点后可以从点击处重新播放。

看了一下原来的版本,发现同时使用了setTimeout和setInterval,两者配合实现点线播放。

简单结构如下

        function test() {
setInterval(function () {
console.log("interval");
//省略插值方法得到arr
(...)
play(arr);
}, 2000);
}
function play(arr) {
setTimeout(function () {
play(arr);
console.log("setTimeout");
}, 40);
}

我觉得这个结构欠妥,两个定时器配合必定会出现失误!因此重构了一版,将两个定时器改为一个,用setInterval解决。

但是此时我并不知道欠妥欠在什么地方,缺乏理论支持,现在闲下来仔细研究了一下

找问题

在仔细研究了旧版本后,我先把旧版本结构扒了出来,排除其他因素,自己模拟了一个简单版(就是上面的代码)

setTimeout:在执行时,是在载入后延迟指定时间后,去执行一次表达式,仅执行一次

setInterval:在执行时,它从载入后,每隔指定的时间就执行一次表达式

  • 实验一:在使用setInterval和setTimeout方法上,并没有什么问题,决定跑一下,结果如下

从结果得出两点结论

  1. setTimeout与setInterval并不是50倍速度配合运行着
  2. 两次interval间,timeout运行的次数越来越多,表明setInterval运行间隔越来越长,延迟越来越大
  • 实验二:加一点人工干预再执行
        function test() {
setInterval(function () {
console.log("interval");
play();
}, 2000);
}
function play() {
//延迟执行
for (var i = 0; i < 100000000; i++) { }
setTimeout(function () {
play();
console.log("setTimeout");
}, 40);
}

从结果得出两点结论

  1. setInterval可能会随函数处理时间,减少间隔
  2. 推测,因为Javascript是单线程的,setInterval和setTimeout是放队列里执行的,很容易受到回调事件影响
  • 实验三:拖动缩放浏览器

从结果得出结论

  1. 当浏览器标签切换到其他页面,或者浏览器最小化,会影响计时器,两者会出现间隔减小

涉及知识点

综上实验结果,网上搜集了一些资料能说明问题:

  1. JavaScript是单线程,但是浏览器是多线程,Javascript是浏览器多线程中的一个线程。(图参考自:https://www.cnblogs.com/tesky0125/p/4619549.html)

  1. Javascript会把执行的回调函数、浏览器的触发事件、UI渲染事件,先放到队列中,队列根据先进先出的规则,依次执行他们,当执行到队列中的setInterval时很难保证其与setTimeout同步关系还保持。
  2. setInterval无视代码错误:代码报错,但是setInterval依旧会按时执行,不会中断。
  3. setInterval无视网络延迟:如果调用ajax或其他服务,他不会管是否返回回调,会继续按时执行。
  4. setInterval不保证执行:因为setInterval会定时执行,如果函数逻辑很长,间隔时间内执行不完,后续方法会被抛弃。
  5. 会受浏览器状态影响,tab切换、最小化等

解决方案

在做轨迹播放时,setInterval的延迟还在可接受范围之内,但是网上给出的最佳解决方案是用setTimeout做。

setTimeout只会执行一次,在执行完成后,重新启动新的Timeout,时间runtime计算设置为差时,减少出现间隔越来越大的情况

        function test() {
//runTime,计算差时
runTime = 1000 - 执行耗时;
setTimeout(callback, runTime);
}
setTimeout(test, 1000);

JavaScript 关于setTimeout与setInterval的小研究的更多相关文章

  1. Javascript的setTimeOut()和setInterval()的定时器用法

    Javascript用来处理延时和定时任务的setTimeOut和setInterval函数应用非常广泛,它们都用来处理延时和定时任务,比如打开网页一段时间后弹出一个登录框,页面每隔一段时间发送异步请 ...

  2. JavaScript的setTimeout和setInterval的深入理解

    发表过一片博客<跟着我用JavaScript写计时器>,比较基础.....有网友说应该写一下setTimeout的原理和机制,嗯,今天就来写一下吧: 直奔主题:setTimeout和set ...

  3. Javascript中setTimeout和setInterval的区别和使用

    在javascript中,window对象有两个主要的定时方法,分别是setTimeout 和 setInterval,其语法基本上相同,但是完成的功能取有区别. setTimeout方法是定时程序, ...

  4. JavaScript的setTimeout()和setInterval()

    1. setTimeout()方法 作用:在制定的毫秒数后调用函数或计算表达式 语法: setTimeout(code,millisec) 实例: function timedMsg() { var ...

  5. JavaScript中setTimeout()和setInterval()的区别

    含义: setTimeout()和setInterval()经常被用来处理延时和定时任务.使用setTimeout()处理延时任务,而使用setInterval()方法处理定时任务: setTimeo ...

  6. JavaScript———从setTimeout与setInterval到AJAX异步

    setTimeout与setInterval执行 首先我们看一下以下代码打印结果 console.log(1); setTimeout(function() { console.log(2); },1 ...

  7. javascript使用setTimeout、setInterval时找不到变量的问题

    我们在某个作用域内或者在自己定义的一个类里调用setTimeout.setInterval会经常会遇到找不到某个变量的错误. 比如下面这个例子: window.onload = function(){ ...

  8. javascript的setTimeout以及setInterval休眠问题。

    前端码农们在做项目中时候,必定不可少的需要做到轮播效果.但是有些特殊的需求,比如: 需要做到第一个容器内容轮播滚动之后,第二个容器内部再轮播滚动,再第三个容器内容轮播滚动. 这时候我的一开始的思路是: ...

  9. javascript定时器:setTimeout与setInterval

    概述: setTimeout:在指定的延迟时间之后调用一个函数或者执行一个代码片段,只执行一次: setInterval:周期性地调用一个函数(function)或者执行一段代码,重复执行: 语法格式 ...

随机推荐

  1. Spring Boot从零入门1_详述

    本文属于原创,转载注明出处,欢迎关注微信小程序`小白AI博客` 微信公众号`小白AI`或者网站 [https://xiaobaiai.net](https://xiaobaiai.net) ![](h ...

  2. 百万年薪python之路 -- MySQL数据库之 用户权限

    MySQL用户授权 (来自于https://www.cnblogs.com/dong-/p/9667787.html) 一. 对新用户的增删改 1. 增加用户 : ①. 指定某一个用户使用某一个ip登 ...

  3. windows下Python开发错误记录以及解决方法

    windows下使用pip提示ImportError: cannot import name 'main' 原因:将pip更新为10.0.0后库里面的函数有所变动造成这个问题 解决方法:先卸载现在的p ...

  4. java Int数据工具类

    1.在使用tcp协议传输数据时,使用到的 Int 数据的工具类方法 //将 Int 数据转换成字节数组 public static byte[] intToByteArray(int data){ b ...

  5. hdfs 文件系统命令操作

    hdfs 文件系统命令操作 [1]hdfs dfs -ls [目录]. 显示所有文件 hdfs dfs -ls -h /user/20170214.txt 显示文件时,文件大小以人易读的形式显示 [2 ...

  6. Spring Boot Mail 实现邮件发送

    此 demo 主要演示了 Spring Boot 如何整合邮件功能,包括发送简单文本邮件. 邮件服务在开发中非常常见,比如用邮件注册账号.邮件作为找回密码的途径.用于订阅内容定期邮件推送等等,下面就简 ...

  7. Veins(车载通信仿真框架)入门教程

    Veins入门教程——教你如何下手研究 目录 Veins入门教程——教你如何下手研究 目录 废话少说! 讲解omnetpp.ini!(挑关键的) 讲解RSUExampleScnario.ned! 注意 ...

  8. vue 父子组件通信详解

    这是一篇详细讲解vue父子组件之间通信的文章,初始学习vue的时候,总是搞不清楚几个情况 通过props在父子组件传值时,v-bind:data="data",props接收的到底 ...

  9. kubernetes实战(二十七):CentOS 8 二进制 高可用 安装 k8s 1.16.x

    1. 基本说明 本文章将演示CentOS 8二进制方式安装高可用k8s 1.16.x,相对于其他版本,二进制安装方式并无太大区别.CentOS 8相对于CentOS 7操作更加方便,比如一些服务的关闭 ...

  10. weex不支持类的动态追加

    做一个weex项目时遇到需要根据状态动态改变样式的功能,本来想通过判断属性追加类的方式实现,如下: :class="['long-news',{'bold-txt':noRead}]&quo ...