setInterval计时器不准的问题解决方法

  在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

  ......

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