背景
项目中要每隔一分钟同步数据,需要用到计时器,定时请求数据。我用的是
setInterval
,通常我们用就是把需要计时的东西放到方法体内,设置即使时间就OK了。但是随着执行的次数增多,误差就会越来越大。
常规写法代码展示
let startTime = new Date().getTime(),
count = 0,
interval = 1000;
setInterval(() => {
count++;
/*
... // 要执行的代码
*/
console.log(
new Date().getTime() - (startTime + count * interval) + "ms"
);
}, interval);
分析原因
setInterval
实现的计时器,根据打印的误差时间可知道,刚开始几毫秒的误差还能接受,但是你在页面操作或者有一些阻塞,这个延迟会越来越大。
究其原因,setInterval
指定的是“开始执行”之间的间隔,并不考虑每次任务执行本身所消耗的时间。setInterval
源于js的单线程,运行的时间会调取计算机资源,如果计算机现在在运行其他的,单线程的就得等着。这一次执行花费时间长一点,下一次执行时间就会快一点。
解决方案
获取每次的误差,根据差值动态调整执行回调的间隔时间
let startTime = new Date().getTime(),
count = 0,
interval = 1000,
offset = 0; //误差时间
let nextTime = interval - offset; //原本间隔时间 - 误差时间
this.selectMsgBoxData();
setInterval(() => {
count++;
offset = new Date().getTime() - (startTime + count * interval);
nextTime = interval - offset;
/*
... // 要执行的代码
*/
console.log(
interval + "间隔时间",
new Date().getTime() - (startTime + count * interval) + "ms"
);
}, nextTime);
···