使用 setInterval 模拟实现 setTimeout
通过 setInterval 的循环特性来模拟 setTimeout 的延迟执行功能,理解定时器的底层原理
问题
setTimeout 用于在指定延迟后执行一次回调函数,而 setInterval 会周期性地重复执行。本题要求使用 setInterval 来模拟实现 setTimeout 的功能,即:在指定时间后执行一次回调,并且能够被清除。
这道题考察了对 JavaScript 定时器机制的理解,以及如何通过循环定时器实现单次执行的逻辑。
解答
/**
* 使用 setInterval 模拟实现 setTimeout
* @param {Function} callback - 延迟执行的回调函数
* @param {number} delay - 延迟时间(毫秒)
* @param {...any} args - 传递给回调函数的参数
* @returns {number} 定时器 ID,用于清除定时器
*/
function mySetTimeout(callback, delay, ...args) {
// 使用 setInterval 创建一个循环定时器
const timer = setInterval(() => {
// 执行回调函数,传入参数
callback(...args);
// 执行完毕后立即清除定时器,确保只执行一次
clearInterval(timer);
}, delay);
// 返回定时器 ID,用于外部清除
return timer;
}
/**
* 清除通过 mySetTimeout 创建的定时器
* @param {number} timerId - 定时器 ID
*/
function myClearTimeout(timerId) {
clearInterval(timerId);
}
使用示例
// 示例 1:基本使用
console.log('开始执行');
mySetTimeout(() => {
console.log('2秒后执行');
}, 2000);
// 示例 2:传递参数
mySetTimeout((name, age) => {
console.log(`姓名:${name},年龄:${age}`);
}, 1000, '张三', 25);
// 示例 3:清除定时器
const timerId = mySetTimeout(() => {
console.log('这段代码不会执行');
}, 3000);
// 在定时器触发前清除
myClearTimeout(timerId);
// 示例 4:链式调用模拟
mySetTimeout(() => {
console.log('第一步');
mySetTimeout(() => {
console.log('第二步');
mySetTimeout(() => {
console.log('第三步');
}, 1000);
}, 1000);
}, 1000);
// 示例 5:与原生 setTimeout 对比
console.log('--- 对比测试 ---');
const start = Date.now();
mySetTimeout(() => {
console.log(`mySetTimeout 执行时间: ${Date.now() - start}ms`);
}, 1000);
setTimeout(() => {
console.log(`setTimeout 执行时间: ${Date.now() - start}ms`);
}, 1000);
关键点
-
思路:利用
setInterval创建定时器,在回调函数执行后立即调用clearInterval清除定时器,从而实现只执行一次的效果 -
参数传递:使用剩余参数
...args收集额外参数,并通过展开运算符传递给回调函数,保持与原生setTimeout的参数传递方式一致 -
返回值处理:返回
setInterval的定时器 ID,使得外部可以通过clearInterval提前清除定时器 -
清除机制:提供
myClearTimeout函数,本质上调用clearInterval,保持 API 的一致性 -
执行时机:
setInterval和setTimeout的执行时机基本一致,都是在指定延迟后将回调函数加入事件队列 -
注意事项:虽然功能相似,但
setInterval的精度可能略有不同,在高精度场景下需要注意误差
目录