在js中如果打算使用setInterval进行倒数,计时等功能,往往是不准确的,因为setInterval的回调函数并不是到时后立即执行,而是等系统计算资源空闲下来后才会执行.而下一次触发时间则是在setInterval回调函数执行完毕之后才开始计时,所以如果setInterval内执行的计算过于耗时,或者有其他耗时任务在执行,setInterval的计时会越来越不准,延迟很厉害.

下面的代码可以说明这个问题

var startTime = new Date().getTime();
var count = 0;
//耗时任务
setInterval(function(){
var i = 0;
while(i++ < 100000000);
}, 0);
setInterval(function(){
count++;
console.log(new Date().getTime() - (startTime + count * 1000));
}, 1000);

代码里输出了setInterval触发时间和应该正确触发时间的延迟毫秒数

176
340
495
652
807
961
1114
1268
1425
1579
1734
1888
2048
2201
2357
2521
2679
2834
2996
......

可以看到延迟是越来越严重的.

为了在js里可以使用相对准确的计时功能,我们可以

var startTime = new Date().getTime();
var count = 0;
setInterval(function(){
var i = 0;
while(i++ < 100000000);
}, 0);
function fixed() {
count++;
var offset = new Date().getTime() - (startTime + count * 1000);
var nextTime = 1000 - offset;
if (nextTime < 0) nextTime = 0;
setTimeout(fixed, nextTime); console.log(new Date().getTime() - (startTime + count * 1000));
}
setTimeout(fixed, 1000);

代码里,通过1000(也就是周期时间)减去当前时间和准确时间的差距,来算出下次触发的时间,从而修正了当前触发的延迟.

下面是输出

186
200
230
271
158
899
900
899
900
899
899
899
902
899
418
202
232
266
145
174
192
214
242
268
149
179
214
......

可以看到虽然触发时间并非绝对准确,但由于每次触发都进行及时修正,所以并没有造成误差积累.

解决setInterval计时器不准的问题的更多相关文章

  1. setInterval计时器延时问题

    计时器延时问题 js计时器 使用setTimeout.setInterval函数时,第二个参数的设置的时间间隔t是自该函数(setTimeout(f1,t).setInterval(f1,t))被调用 ...

  2. setTimeout setInterval 计时器

    setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式. 返回值:返回一个 ID(数字),可以将这个ID传递给 clearTimeout() 来取消执行. 案例: 点击按钮开始,停止时 ...

  3. 为什么JS是单线程?JS中的Event Loop(事件循环)?JS如何实现异步?setimeout?

    https://segmentfault.com/a/1190000012806637 https://www.jianshu.com/p/93d756db8c81 首先,请牢记2点: (1) JS是 ...

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

    setInterval()和setTimeout()方法都是js原生的定时方法,当然它们两个的作用也是不同的,并且最近在做上下滚动公告栏的时候,发现了setInterval()非常令人抓狂的问题,那就 ...

  5. JS window对象取消计时器clearInterval() clearInterval() 方法可取消由 setInterval() 设置的交互时间。

    取消计时器clearInterval() clearInterval() 方法可取消由 setInterval() 设置的交互时间. 语法: clearInterval(id_of_setInterv ...

  6. JS Window对象 计时器setInterval() 在执行时,从载入页面后每隔指定的时间执行代码。

    计时器setInterval() 在执行时,从载入页面后每隔指定的时间执行代码. 语法: setInterval(代码,交互时间); 参数说明: 1. 代码:要调用的函数或要执行的代码串. 2. 交互 ...

  7. 关于setInterval的坑

    一道面试题:“setInterval和setTimeout有什么区别” “如果setInterval计时器的回调函数执行完需要5秒,而计时器时间间隔为3秒,那会发生什么?” 验证代码 让程序滞留固定时 ...

  8. js_计时器之setInterval

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. javascript运动学教程

    本文系笔者学习原生javascript动效的笔记.内容基于某非著名培训机构的视频教程.并重新做了归类整理.删除了一些过时的内容.并重做了GIF图,加上了自己的一些分析. 一. 运动学基础 引子:从左到 ...

随机推荐

  1. 黄聪:Mysql数据库还原备份提示MySQL server has gone away 的解决方法(备份文件数据过大)

    使用mysql做数据库还原的时候,由于有些数据很大,会出现这样的错误:The MySQL Server returned this Error:MySQL Error Nr. MySQL server ...

  2. C# 如何将字符串形式的” \\u1234 “ 为 “ \u1234” 的unicode编码解码为中文

    using System.Text.RegularExpressions; decodedStr = Regex.Unescape(escapeUnicodeStr);

  3. 黄聪:Discuz!X3.2 如何配置超级版主或者某些管理员,允许管理用户组或者权限

    点击后台-->站长-->后台管理团队-->新增用户(用户名)用户管理员即可

  4. NeHe OpenGL教程 第二十三课:球面映射

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  5. Linux重置mysql密码(转载)

    From:http://hi.baidu.com/mcspring/item/6358ee27afe7e1c8a5275ab7 首先,必须拥有MySQL操作的所有权限: 其次,停止MySQL服务: / ...

  6. 在linux下通过sh运行java程序

    1.导出jar包放在目录下,如/home 2.通过vi创建sh文件如:test.sh,内容如:java -jar test1.jar com.wzh.test.test & 3.运行命令:sh ...

  7. Java多线程之简单的线程同步实例

    数据类: package Thread.MyCommon; public class Data { public int num = 0; public synchronized int getEve ...

  8. Android之BroadcastReceiver1

    1.触发发送广播 public class MainActivity extends Activity { private Button sendButton; @Override protected ...

  9. Python中在脚本中引用其他文件函数的方法

    在导入文件的时候,Python只搜索当前脚本所在的目录,加载(entry-point)入口脚本运行目录和sys.path中包含的路径例如包的安装地址.所以如果要在当前脚本引用其他文件,除了将文件放在和 ...

  10. linux下安装nginx、pcre、zlib、openssl

    1.安装nginx之前需要安装PCRE库的安装  最新下载地址   ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ tar –zxvf p ...