用 setTimeout 实现 setInterval

89 阅读2分钟

🚀 setTimeout 实现setInterval :一篇搞懂! 🚀

在前端开发中,setInterval 是一个常用的定时器函数,但你知道如何用 setTimeout 实现 setInterval 的功能吗?今天我们就来彻底搞懂这个问题!👇


1. setInterval 的问题

setInterval 是一个周期性执行的定时器,但它有一些潜在的问题:

  1. 误差累积:如果回调函数执行时间过长,会导致定时器的间隔不准确。
  2. 难以控制:一旦启动,setInterval 会一直执行,直到手动清除。

2. setTimeout 实现setInterval

通过递归调用 setTimeout,可以实现类似 setInterval 的功能,同时避免上述问题。

2.1 基本实现

function mySetInterval(callback, interval) {
  let timerId;

  const execute = () => {
    callback(); // 执行回调函数
    timerId = setTimeout(execute, interval); // 递归调用
  };

  timerId = setTimeout(execute, interval); // 启动定时器

  return () => clearTimeout(timerId); // 返回清除函数
}

// 使用示例
const stop = mySetInterval(() => {
  console.log('Hello, World!');
}, 1000);

// 5 秒后停止定时器
setTimeout(() => {
  stop();
}, 5000);

2.2 优点

  1. 避免误差累积:每次回调函数执行完后,再设置下一次的定时器。
  2. 灵活控制:可以随时停止定时器。

3. 带参数的mySetInterval

如果需要传递参数给回调函数,可以稍作修改。

3.1 实现

function mySetInterval(callback, interval, ...args) {
  let timerId;

  const execute = () => {
    callback(...args); // 执行回调函数,并传递参数
    timerId = setTimeout(execute, interval); // 递归调用
  };

  timerId = setTimeout(execute, interval); // 启动定时器

  return () => clearTimeout(timerId); // 返回清除函数
}

// 使用示例
const stop = mySetInterval((name) => {
  console.log(`Hello, ${name}!`);
}, 1000, 'Alice');

// 5 秒后停止定时器
setTimeout(() => {
  stop();
}, 5000);

4. 支持首次立即执行

如果需要首次立即执行回调函数,可以稍作修改。

4.1 实现

function mySetInterval(callback, interval, immediate = false, ...args) {
  let timerId;

  const execute = () => {
    callback(...args); // 执行回调函数,并传递参数
    timerId = setTimeout(execute, interval); // 递归调用
  };

  if (immediate) {
    callback(...args); // 首次立即执行
  }

  timerId = setTimeout(execute, interval); // 启动定时器

  return () => clearTimeout(timerId); // 返回清除函数
}

// 使用示例
const stop = mySetInterval((name) => {
  console.log(`Hello, ${name}!`);
}, 1000, true, 'Alice');

// 5 秒后停止定时器
setTimeout(() => {
  stop();
}, 5000);

5. 总结

  • setTimeout 实现setInterval:通过递归调用 setTimeout,可以避免 setInterval 的误差累积问题。
  • 优点:灵活控制、避免误差累积。
  • 扩展功能:支持传递参数、首次立即执行。

如果你对 setTimeoutsetInterval 还有疑问,欢迎在评论区讨论!💬