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

先看以下两看计时器

setTimeout版

function test(){
count += 1;
console.log(`第${count}次开始 ${getTime.now() - startTime} ID:${t}`); // 显示开始时间 console.log(`第${count}次结束 ${getTime.now() - startTime}`); // 显示结束时间 //count<1000 && setTimeout(test,500); //这样写没有ID
if(count<1000) t=setTimeout(test,500); //这样写没有ID
} let count = -1;
let getTime = window.performance;
let startTime = getTime.now();
var t; test(); // 300ms间隔

运行结果

误差很大,原因js是单线程,而setTimeout两次时间间隔为timer执行时间+interval延时时间,久而久之积累的误差就大了

setInterval版
function sleep(time) {
let startTime = window.performance.now();
while (window.performance.now() - startTime < time) {}
} function test(){
count++;
console.log(`第${count}次开始 ${getTime.now() - startTime}`);
// 显示开始时间
//sleep(100); // 程序滞留500ms
console.log(`第${count}次结束 ${getTime.now() - startTime}`); // 显示结束时间
count>1000 && clearInterval(t);
} let count = 0;
let getTime = window.performance;
let startTime = getTime.now(); var t = setInterval(test , 500); // 300ms间隔

最后结果:

测了两次结果差很多,可能应该是第一次我切出当前页的原因,已至getTime.now();出错,从第二个结果看,还是很精准的,但是,

第一种写法:

1
2
3
4
funciton xxx(){
//函数代码,此处执行时间约20毫秒
setTimeout(xxx,10)
}

第二种写法:

1
2
3
4
funciton xxx(){
//函数代码,此处执行时间约20毫秒
}
setInterval(xxx,10)

第一种写法中,只有执行完20ms的代码后,再等10ms才会开始下一个循环;

第二种写法中,无论有没有执行完20ms的代码,10ms后都会开始下一个循环

setTimeout优化版:

var startTime0 = new Date().getTime();
let count = 0;
let getTime = window.performance;
let startTime = getTime.now();
var t;
//setTimeout(test,500); // 300ms间隔 setTimeout(function () {
count += 1;
console.log(`第${count}次开始 ${getTime.now() - startTime}`);
// 显示开始时间
//sleep(500); // 程序滞留500ms var offset = getTime.now() - (startTime + count * 500);
var nextTime = 500 - offset;
//console.log(nextTime);
if (nextTime < 0) nextTime = 0;
console.log(`第${count}次结束 ${getTime.now() - startTime} 下次延时:${nextTime}`); // 显示结束时间
if(count<1000){setTimeout(arguments.callee, nextTime);} }, 500)

setTimeout优化后的结果

setTimeout优化说明:

1、最大的特点就是动态修正当前触发的延迟时间。

2、为什么选择setTimeout,因为setTimeout更方便调节延迟时间。

3、使用performance.now()是当前时间与performance.timing.navigationStart的时间差,以微秒(百万分之一秒)为单位的时间,与 Date.now()-performance.timing.navigationStart的区别是不受系统程序执行阻塞的影响,因此更加精准。关于performance的更多内容

4、第二个setTimeout()调用使用了agrument.callee 来获取当前实行函数的引用,并设置另外一个新定时器。这样做可以保证在代码执行完成前不会有新的定时器插入。(来自

相关链接:https://blog.csdn.net/acm765152844/article/details/51298915

js定时器优化的更多相关文章

  1. javascript定时器,取消定时器,及js定时器优化方法

    通常用的方法: 启动定时器: window.setInterval(Method,Time) Method是定时调用的js方法 Time是间隔时间,单位是毫秒 取消定时器: clearInterval ...

  2. JS定时器不可靠的原因及解决方案

    前言 在工作中应用定时器的场景非常多,但你会发现有时候定时器好像并没有按照我们的预期去执行,比如我们常遇到的setTimeout(()=>{},0)它有时候并不是按我们预期的立马就执行.想要知道 ...

  3. 应用r.js来优化你的前端

    r.js是requireJS的优化(Optimizer)工具,可以实现前端文件的压缩与合并,在requireJS异步按需加载的基础上进一步提供前端优化,减小前端文件大小.减少对服务器的文件请求.要使用 ...

  4. js性能优化-事件委托

    js性能优化-事件委托 考虑一个列表,在li的数量非常少的时候,为每一个li添加事件侦听当然不会存在太多性能方面的问题,但是当列表非常的长,长到上百上千甚至上万的时候(当然只是一个解释,实际工作中很少 ...

  5. js定时器的使用(实例讲解)

    在javascritp中,有两个关于定时器的专用函数,分别为: 1.倒计定时器:timename=setTimeout("function();",delaytime);2.循环定 ...

  6. 移动Web与js定时器暂停或不准确计时的问题解决

    PC 上的 Firefox.Chrome 和 Safari 等浏览器,都会自动把未激活页面中的 JavaScript 定时器(setTimeout.setInterval)间隔最小值改为 1 秒以上: ...

  7. js定时器 特定时间执行某段程序的例子

    定时器想必大家并不陌生吧,在本文为大家详细介绍下js中是如何实现定时器的,具体原理及代码如下. 例子: $(function(){ var handler = function(){ //www.jb ...

  8. js定时器setInterval()与setTimeout()

    js定时器setInterval()与setTimeout() 1.setTimeout(Expression,DelayTime),在DelayTime过后,将执行一次Expression,setT ...

  9. js 性能优化利器:prepack

    1. js 性能优化 js 本身是没有像 python 一样的预编译功能,更没有像 java 一样的编译功能,所以,这里所说的 js 代码预编译 只是通过工具实现的类似功能而已. 这就要提到 prep ...

随机推荐

  1. 强制禁用gitlab的双因子认证:Two-Factor Authentication

    (一)问题描述: 此博客解决如下问题:禁用gitlab的双因子认证 禁用前,如图(此时,你在gitlab中什么也干不了) (二)思路分析: 百度了很多方法,都不可靠(如不可靠的说明:https://s ...

  2. eslint 代码规范2

    eslint 规则修改 需要修改规则:文件[.eslintrc.js] 在句末是不能有分号的,若想加分号, 报错: 添加代码: 'semi': ['error', 'always'] 不要使用制表符. ...

  3. JVM调优之jstack找出最耗cpu的线程、定位代码

    jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多.下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有 ...

  4. PHP适配器模式

    [IDatabase.php] <?php /** * 适配器模式 * 可以将不同的函数接口封装成统一的API * 应用举例1:数据库操作 mysql/mysqli/pdo * 应用举例2:缓存 ...

  5. centos7 yum 安装mysql5.6

    这里用科技大学的mysql yum源官方的源太慢 [root@localhost ~]# rpm -ivh http://mirrors.ustc.edu.cn/mysql-repo/mysql-co ...

  6. bat脚本简单命令

    1.if 判断 (1.1)判断字符串是否为空: if "%var1%" == " " ( echo null) else(echo not null ) (1. ...

  7. ubuntu 的远程命令行,老是不能支持联想

    首先发现没有source命令,非常奇怪,google发现是dash命令的问题. $ls -l `which sh` /bin/sh -> dash $sudo dpkg-reconfigure ...

  8. Groovy动态解析

    A:前面需要说些什么吗? B:不需要吗? A:需要吗? 解析方式一:通过指定的paths来初始化GroovyScriptEngine //通过指定的paths来初始化GroovyScriptEngin ...

  9. LR、Poly2、FM、FFM

    1. LR LR的linear Margin: 假设特征之间是相互独立的,忽略了feature pair等高阶信息:在LR中,特征组合等高阶信息是通过特征工程在特征侧引入的,那么有哪些模型不需要通过特 ...

  10. WebService/WCF/WebAPI 之间的区别

    Web Service 1.数据的格式基于SOAP协议 2.数据的传输只支持HTTP协议 3.它只能部署在IIS上 WCF 1.数据的格式基于SOAP协议 2.数据的传输支持HTTP,HTTPS,TC ...