🤔什么? JS中有四种定时器!你都知道吗😇😇

202 阅读2分钟

setTimeout

setTimeout用于在指定的时间后将函数加入任务队列。它返回一个timeoutID,可以用来取消这个计时器。

const timeoutID = setTimeout(function() {
  // 任务代码
}, 2000); // 2秒后执行

// 取消计时器
clearTimeout(timeoutID);

setInterval

setInterval: setInterval用于每隔一定时间间隔将函数加入任务队列。它同样返回一个intervalID,可以用来取消这个计时器。

setInterval在每次把任务push到任务队列前,都要进行一下判断(看上次的任务是否仍在队列中,进行是否加入)

const intervalID = setInterval(function() {
  // 任务代码
}, 1000); // 每隔1秒执行一次
// 取消计时器
clearInterval(intervalID);

requestAnimationFrame

requestAnimationFrame: requestAnimationFrame中函数在浏览器渲染每一帧都进行触发

浏览器的重绘时间相关

function animate() {
  // 动画逻辑
}
requestAnimationFrame(animate);

setImmediate(已废弃)

setImmediate: setImmediate的功能类似于setTimeout,但是它会在当前事件结束后立即执行回调函数,而不是等待指定的时间。

const immediateID = setImmediate(function() {
  // 任务代码
});
// 取消立即执行
clearImmediate(immediateID);

这四个方法的应用

  1. requestAnimationFrame
  • 需要频繁触发
  1. setTimeout
  • 仅调用一次。
  1. setInterval
  • 用于创建重复执行的计时器、轮询和非重要操作。
  1. setImmediate
  • 事件完成之后立即执行某些清理工作
const fs = require('fs');
fs.readFile('example.txt', (err, data) => {
    if (err) throw err;
    console.log('File read');
    setImmediate(() => {
        console.log('Cleanup work done');
    });
});

setImmediate在 Vue Nexttick与 React 调度器的使用

nextTick

2.5版本,Vue引入MessageChannel,nextTick的实现优先使用setImmediate,平台不支持则使用MessageChannel,再不支持才使用Promise,最后用setTimeout兜底。

不过到了2.6版本以后,nextTick又改回原来的Promise实现。

if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  timerFunc = () => {
    setImmediate(nextTickHandler)
  }
} else if (typeof MessageChannel !== 'undefined' && (
  isNative(MessageChannel) ||
  MessageChannel.toString() === '[object MessageChannelConstructor]'
)) {
  const channel = new MessageChannel()
  const port = channel.port2
  channel.port1.onmessage = nextTickHandler
  timerFunc = () => {
    port.postMessage(1)
  }
} else
  if (typeof Promise !== 'undefined' && isNative(Promise)) {
    const p = Promise.resolve()
    timerFunc = () => {
      p.then(nextTickHandler)
    }
  } else {
    timerFunc = () => {
      setTimeout(nextTickHandler, 0)
    }
  }

React 调度器

let schedulePerformWorkUntilDeadline;
if (typeof localSetImmediate === 'function') {
  schedulePerformWorkUntilDeadline = () => {
    localSetImmediate(performWorkUntilDeadline);
  };
} else if (typeof MessageChannel !== 'undefined') {
  // DOM and Worker environments.
  // We prefer MessageChannel because of the 4ms setTimeout clamping.
  const channel = new MessageChannel();
  const port = channel.port2;
  channel.port1.onmessage = performWorkUntilDeadline;
  schedulePerformWorkUntilDeadline = () => {
    port.postMessage(null);
  };
} else {
  // We should only fallback here in non-browser environments.
  schedulePerformWorkUntilDeadline = () => {
    localSetTimeout(performWorkUntilDeadline, 0);
  };
}

setTimeout 实现 setInterval

setInterval在每次把任务push到任务队列前,都要进行一下判断(看上次的任务是否仍在队列中,进行是否加入)

const _setInterval = (callBack, time) => {
    let timeId= 0
    const fn = () => {
      callBack();
      timeId = setTimeout(fn, time);
    }
    timeId = setTimeout(fn, time);
    return timeId
  }
  let a=_setInterval(()=>console.log(1),1000)
  clearTimeout(a)