为什么要使用setTimeout来实现SetInterval?

我们知道setInterval以一定频率来执行一个函数,但是这样有一个问题,加入执行的这个函数相当耗时,超过了我们给定的周期时间,setInterval还会按照约定的时间来执行下次任务吗?

答案是不会,setInterval会等到当前的任务执行完成后,再立即执行下一次的任务,看个例子

setInterval(function interval() {
  for(let i = 0; i < 10000000000; i++);
  console.log('done')
}, 1000)

打印语句出现的时间会超过1s,那么第2s的打印操作也会随着被推迟。参考下图,setInterval每次的时间间隔是从任务开始时间开始算的,尽量与下一次任务的开始执行时间间隔和给定的时间间隔相同,一旦任务的执行时间超过了给定的时间间隔,那么下一次任务会被推迟,下次任务会在本次任务结束后来执行。

 title=

如何使用setTimeout来模拟setInterval?

借助与递归的思路,在上次任务结束后,立即安排下次任务的执行,这样保证上一个任务的结束时间到下一个任务的开始时间和给定时间是相等的

 title=

function setInterval2(fn, ms, ...args) {
  let timeId = null
  function tick() {
    timeId = setTimeout(() => {
      fn(...args)
      tick()
    }, ms)
  }
  fn(...args)
  tick()
  return () => clearTimeout(timeId)
}

function setInterval3(fn, ms, ...args) {
  fn(...args)
  let timeId = setTimeout(function tick() {
    fn(...args)
    timeId = setTimeout(tick, ms)
  }, ms)
  return () => clearTimeout(timeId) // 方便随时取消
}

Tqing
112 声望16 粉丝

引用和评论

0 条评论