在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. vue项目引用 iView 组件——全局安装与按需加载

    框架的热度,出现了不少基于Vue的UI组件库,这次项目用到了 iView 这个组件库.使用方法官网很详细. 官网:https://www.iviewui.com/ 这篇文章主要是记录一下npm 全局安 ...

  2. 前端 CSS 三种引入方式

    CSS三种引入方式 行内样式 内接样式 外部样式 链接式 导入式 行内样式 就是在标签加上style属性设置样式 <!DOCTYPE html> <html lang="e ...

  3. contos mysql 删除

    yum remove mysql mysql-server mysql-libs compat-mysql51rm -rf /var/lib/mysqlrm /etc/my.cnf查看是否还有mysq ...

  4. OpenVPN简介及架构详解

    OpenVPN简介 1 简介    VPN(Virtual Private Network)直译就是虚拟专用通道,是提供给企业之间或者个人与公司之间安全数据传输的隧道. OpenVPN无疑是Linux ...

  5. 微服务——RestTemplate

    GET请求: 第一种:getForEntity: 此方法返回的是ResponseEntity,该对象是Spring对HTTP请求响应的封装. RestTemplate rt = new RestTem ...

  6. poj3259: Wormholes(BF模板题)

    http://poj.org/problem?id=3259 Description While exploring his many farms, Farmer John has discovere ...

  7. Python Socket通信例子

    一.TCP 通信 服务端 #!/usr/bin/env python # -*- coding: utf-8 -*- # server_tcp.py import socket so = socket ...

  8. 通过socket实现http通讯代码理解

    1.首先构造http协议报头: String dd = "GET http://www.baidu.com HTTP/1.1" + "\r\n" + " ...

  9. [ErrorException] "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"?

    Mac上PHP更新到7.3,使用Composer报这个错误 解决办法: composer selfupdate

  10. url请求老是有 之前的部分url

    url请求的时候老是会有之前的部分url <form action="shiro/register" method="POST"> 解决方法,加上本 ...