Search K
Appearance
Appearance
📊 SEO元描述:2024年最新JavaScript定时器教程,详解setTimeout、setInterval、定时器this指向、性能优化、清理机制。包含完整代码示例,适合JavaScript开发者掌握异步编程核心技术。
核心关键词:JavaScript定时器、setTimeout、setInterval、定时器清理、异步编程
长尾关键词:setTimeout怎么用、setInterval用法、定时器this指向、JavaScript定时器清理、定时器性能优化
通过本节定时器详解,你将系统性掌握:
定时器是什么?这是JavaScript异步编程的重要组成部分。定时器是浏览器提供的异步执行机制,也是实现延迟执行和周期性任务的核心工具。
💡 学习建议:深入理解定时器机制对于掌握JavaScript异步编程和性能优化至关重要
setTimeout 用于延迟执行代码:
// 🎉 setTimeout基础用法示例
class TimeoutManager {
constructor() {
this.timeouts = new Map();
this.timeoutCounter = 0;
}
// 基本setTimeout用法
basicUsage() {
console.log('开始执行');
// 基本延迟执行
setTimeout(() => {
console.log('1秒后执行');
}, 1000);
// 带参数的延迟执行
setTimeout(function(name, age) {
console.log(`用户信息: ${name}, ${age}岁`);
}, 2000, 'Alice', 25);
// 返回定时器ID
const timerId = setTimeout(() => {
console.log('这个不会执行');
}, 3000);
// 清除定时器
clearTimeout(timerId);
console.log('设置完成');
}
// 高级setTimeout用法
advancedUsage() {
// 递归setTimeout实现setInterval效果
let count = 0;
const recursiveTimeout = () => {
console.log(`递归执行第 ${++count} 次`);
if (count < 5) {
setTimeout(recursiveTimeout, 1000);
}
};
setTimeout(recursiveTimeout, 1000);
// 动态延迟时间
let delay = 100;
const dynamicTimeout = () => {
console.log(`延迟 ${delay}ms 执行`);
delay *= 2;
if (delay <= 1600) {
setTimeout(dynamicTimeout, delay);
}
};
setTimeout(dynamicTimeout, delay);
}
// 管理多个定时器
createTimeout(callback, delay, name = null) {
const id = ++this.timeoutCounter;
const timerId = setTimeout(() => {
callback();
this.timeouts.delete(id);
}, delay);
this.timeouts.set(id, {
timerId: timerId,
name: name,
delay: delay,
createdAt: Date.now()
});
return id;
}
// 清除指定定时器
clearTimeout(id) {
const timeout = this.timeouts.get(id);
if (timeout) {
clearTimeout(timeout.timerId);
this.timeouts.delete(id);
return true;
}
return false;
}
// 清除所有定时器
clearAllTimeouts() {
for (const [id, timeout] of this.timeouts) {
clearTimeout(timeout.timerId);
}
this.timeouts.clear();
console.log('已清除所有定时器');
}
// 获取定时器信息
getTimeoutInfo() {
const info = [];
for (const [id, timeout] of this.timeouts) {
info.push({
id: id,
name: timeout.name,
delay: timeout.delay,
age: Date.now() - timeout.createdAt
});
}
return info;
}
}
// 使用setTimeout管理器
const timeoutManager = new TimeoutManager();
// 基础用法演示
timeoutManager.basicUsage();
// 高级用法演示
timeoutManager.advancedUsage();
// 创建管理的定时器
const id1 = timeoutManager.createTimeout(() => {
console.log('管理的定时器1执行');
}, 2000, '定时器1');
const id2 = timeoutManager.createTimeout(() => {
console.log('管理的定时器2执行');
}, 3000, '定时器2');
// 查看定时器信息
setTimeout(() => {
console.log('定时器信息:', timeoutManager.getTimeoutInfo());
}, 1000);
// 5秒后清除所有定时器
setTimeout(() => {
timeoutManager.clearAllTimeouts();
}, 5000);// 🎉 setInterval详解示例
class IntervalManager {
constructor() {
this.intervals = new Map();
this.intervalCounter = 0;
}
// 基本setInterval用法
basicUsage() {
let count = 0;
// 基本周期执行
const intervalId = setInterval(() => {
console.log(`周期执行第 ${++count} 次`);
// 执行5次后停止
if (count >= 5) {
clearInterval(intervalId);
console.log('周期执行结束');
}
}, 1000);
// 带参数的周期执行
let counter = 0;
const paramInterval = setInterval(function(prefix, suffix) {
console.log(`${prefix} ${++counter} ${suffix}`);
if (counter >= 3) {
clearInterval(paramInterval);
}
}, 1500, '计数:', '次');
}
// setInterval vs setTimeout递归
compareIntervalVsTimeout() {
console.log('=== setInterval vs setTimeout递归对比 ===');
// setInterval方式
let intervalCount = 0;
const intervalId = setInterval(() => {
console.log(`setInterval: ${++intervalCount}`);
if (intervalCount >= 3) {
clearInterval(intervalId);
}
}, 1000);
// setTimeout递归方式
let timeoutCount = 0;
const timeoutRecursive = () => {
console.log(`setTimeout递归: ${++timeoutCount}`);
if (timeoutCount < 3) {
setTimeout(timeoutRecursive, 1000);
}
};
setTimeout(timeoutRecursive, 1000);
// 关键区别演示
this.demonstrateDifference();
}
// 演示setInterval和setTimeout递归的区别
demonstrateDifference() {
console.log('=== 执行时间差异演示 ===');
// setInterval - 固定间隔
let intervalStart = Date.now();
let intervalTimes = [];
const intervalDemo = setInterval(() => {
const now = Date.now();
intervalTimes.push(now - intervalStart);
console.log(`setInterval间隔: ${now - intervalStart}ms`);
intervalStart = now;
if (intervalTimes.length >= 3) {
clearInterval(intervalDemo);
console.log('setInterval平均间隔:',
intervalTimes.reduce((a, b) => a + b) / intervalTimes.length);
}
}, 100);
// setTimeout递归 - 执行完成后计时
let timeoutStart = Date.now();
let timeoutTimes = [];
let timeoutCount = 0;
const timeoutDemo = () => {
const now = Date.now();
timeoutTimes.push(now - timeoutStart);
console.log(`setTimeout递归间隔: ${now - timeoutStart}ms`);
timeoutStart = now;
// 模拟耗时操作
const start = Date.now();
while (Date.now() - start < 50) {} // 阻塞50ms
if (++timeoutCount < 3) {
setTimeout(timeoutDemo, 100);
} else {
console.log('setTimeout递归平均间隔:',
timeoutTimes.reduce((a, b) => a + b) / timeoutTimes.length);
}
};
setTimeout(timeoutDemo, 100);
}
// 创建管理的间隔定时器
createInterval(callback, interval, options = {}) {
const {
immediate = false,
maxExecutions = Infinity,
name = null
} = options;
const id = ++this.intervalCounter;
let executionCount = 0;
const execute = () => {
if (executionCount >= maxExecutions) {
this.clearInterval(id);
return;
}
executionCount++;
callback(executionCount);
if (executionCount >= maxExecutions) {
this.clearInterval(id);
}
};
// 立即执行选项
if (immediate) {
execute();
}
const intervalId = setInterval(execute, interval);
this.intervals.set(id, {
intervalId: intervalId,
name: name,
interval: interval,
executionCount: executionCount,
maxExecutions: maxExecutions,
createdAt: Date.now()
});
return id;
}
// 清除指定间隔定时器
clearInterval(id) {
const interval = this.intervals.get(id);
if (interval) {
clearInterval(interval.intervalId);
this.intervals.delete(id);
return true;
}
return false;
}
// 暂停间隔定时器
pauseInterval(id) {
const interval = this.intervals.get(id);
if (interval && !interval.paused) {
clearInterval(interval.intervalId);
interval.paused = true;
interval.pausedAt = Date.now();
return true;
}
return false;
}
// 恢复间隔定时器
resumeInterval(id, callback) {
const interval = this.intervals.get(id);
if (interval && interval.paused) {
const newIntervalId = setInterval(() => {
if (interval.executionCount >= interval.maxExecutions) {
this.clearInterval(id);
return;
}
interval.executionCount++;
callback(interval.executionCount);
if (interval.executionCount >= interval.maxExecutions) {
this.clearInterval(id);
}
}, interval.interval);
interval.intervalId = newIntervalId;
interval.paused = false;
delete interval.pausedAt;
return true;
}
return false;
}
// 获取所有间隔定时器信息
getIntervalInfo() {
const info = [];
for (const [id, interval] of this.intervals) {
info.push({
id: id,
name: interval.name,
interval: interval.interval,
executionCount: interval.executionCount,
maxExecutions: interval.maxExecutions,
paused: interval.paused || false,
age: Date.now() - interval.createdAt
});
}
return info;
}
// 清除所有间隔定时器
clearAllIntervals() {
for (const [id, interval] of this.intervals) {
clearInterval(interval.intervalId);
}
this.intervals.clear();
console.log('已清除所有间隔定时器');
}
}
// 使用setInterval管理器
const intervalManager = new IntervalManager();
// 基础用法演示
intervalManager.basicUsage();
// 对比演示
setTimeout(() => {
intervalManager.compareIntervalVsTimeout();
}, 2000);
// 创建管理的间隔定时器
const intervalId = intervalManager.createInterval(
(count) => {
console.log(`管理的间隔定时器执行第 ${count} 次`);
},
1000,
{
immediate: true,
maxExecutions: 5,
name: '测试间隔定时器'
}
);
// 3秒后暂停
setTimeout(() => {
intervalManager.pauseInterval(intervalId);
console.log('间隔定时器已暂停');
}, 3000);
// 5秒后恢复
setTimeout(() => {
intervalManager.resumeInterval(intervalId, (count) => {
console.log(`恢复后的间隔定时器执行第 ${count} 次`);
});
console.log('间隔定时器已恢复');
}, 5000);// 🎉 定时器this指向问题详解
class TimerThisDemo {
constructor(name) {
this.name = name;
this.count = 0;
this.setupTimerExamples();
}
// 演示this指向问题
setupTimerExamples() {
console.log('=== 定时器this指向问题演示 ===');
// 问题1: 普通函数中的this指向
setTimeout(function() {
console.log('普通函数中的this:', this); // Window对象
// console.log('this.name:', this.name); // undefined
}, 1000);
// 解决方案1: 箭头函数
setTimeout(() => {
console.log('箭头函数中的this:', this); // TimerThisDemo实例
console.log('箭头函数中的this.name:', this.name);
}, 1500);
// 解决方案2: bind方法
setTimeout(function() {
console.log('bind后的this:', this); // TimerThisDemo实例
console.log('bind后的this.name:', this.name);
}.bind(this), 2000);
// 解决方案3: 保存this引用
const self = this;
setTimeout(function() {
console.log('保存引用的self:', self); // TimerThisDemo实例
console.log('保存引用的self.name:', self.name);
}, 2500);
// 解决方案4: call/apply方法
const timerCallback = function() {
console.log('call调用的this:', this); // TimerThisDemo实例
console.log('call调用的this.name:', this.name);
};
setTimeout(() => {
timerCallback.call(this);
}, 3000);
}
// 实际应用示例:计数器
startCounter() {
console.log('=== 计数器示例 ===');
// 错误的方式
setTimeout(function() {
this.count++; // 错误:this不指向实例
console.log('错误方式的count:', this.count); // NaN
}, 1000);
// 正确的方式
setTimeout(() => {
this.count++;
console.log('正确方式的count:', this.count);
}, 1500);
}
// 方法作为回调函数的this问题
methodAsCallback() {
console.log('=== 方法作为回调函数的this问题 ===');
// 定义实例方法
this.instanceMethod = function() {
console.log('实例方法中的this.name:', this.name);
};
// 直接传递方法引用(错误)
setTimeout(this.instanceMethod, 1000); // this指向Window
// 正确的传递方式
setTimeout(() => this.instanceMethod(), 1500);
setTimeout(this.instanceMethod.bind(this), 2000);
}
// 复杂场景:嵌套定时器
nestedTimers() {
console.log('=== 嵌套定时器this问题 ===');
setTimeout(() => {
console.log('外层定时器this.name:', this.name);
// 嵌套定时器中的this
setTimeout(() => {
console.log('内层定时器this.name:', this.name);
// 更深层嵌套
setInterval(() => {
this.count++;
console.log(`嵌套间隔定时器 count: ${this.count}`);
if (this.count >= 3) {
console.log('嵌套定时器结束');
}
}, 500);
}, 1000);
}, 1000);
}
}
// 使用this指向演示
const thisDemo = new TimerThisDemo('测试对象');
// 启动各种演示
thisDemo.startCounter();
setTimeout(() => {
thisDemo.methodAsCallback();
}, 4000);
setTimeout(() => {
thisDemo.nestedTimers();
}, 8000);
// 类方法中的定时器最佳实践
class BestPracticeTimer {
constructor(name) {
this.name = name;
this.timers = [];
}
// 最佳实践:统一的定时器创建方法
createTimer(callback, delay, isInterval = false) {
const boundCallback = callback.bind(this);
const timerId = isInterval
? setInterval(boundCallback, delay)
: setTimeout(boundCallback, delay);
this.timers.push({
id: timerId,
type: isInterval ? 'interval' : 'timeout',
delay: delay
});
return timerId;
}
// 示例方法
startProcess() {
// 使用统一方法创建定时器
this.createTimer(function() {
console.log(`${this.name}: 延迟执行完成`);
}, 1000);
this.createTimer(function() {
console.log(`${this.name}: 周期执行`);
}, 2000, true);
}
// 清理所有定时器
cleanup() {
this.timers.forEach(timer => {
if (timer.type === 'interval') {
clearInterval(timer.id);
} else {
clearTimeout(timer.id);
}
});
this.timers = [];
console.log(`${this.name}: 所有定时器已清理`);
}
}
// 使用最佳实践
const bestPractice = new BestPracticeTimer('最佳实践示例');
bestPractice.startProcess();
// 5秒后清理
setTimeout(() => {
bestPractice.cleanup();
}, 5000);核心应用场景:
💼 开发价值:深入理解定时器机制是JavaScript异步编程的基础,对于构建高质量的Web应用至关重要
通过本节定时器详解的学习,你已经掌握:
A: setTimeout执行一次后结束,setInterval会周期性重复执行;setInterval可能因为执行时间过长导致间隔不准确,setTimeout递归更精确。
A: 定时器回调函数是在全局作用域中执行的,普通函数的this会指向window;使用箭头函数、bind()或保存this引用可以解决。
A: 及时清理不需要的定时器,在组件销毁时清除所有定时器,避免在定时器中引用大对象。
A: 现代浏览器的最小延迟通常是4ms,但在某些情况下可能更长。不要依赖精确的短时间间隔。
A: 当需要精确控制执行间隔,或者回调函数执行时间可能较长时,使用setTimeout递归更合适。
// 🎉 高级定时器管理系统
class AdvancedTimerScheduler {
constructor() {
this.timers = new Map();
this.groups = new Map();
this.globalId = 0;
this.paused = false;
this.statistics = {
created: 0,
executed: 0,
cleared: 0
};
}
// 创建定时器
schedule(callback, delay, options = {}) {
const {
type = 'timeout', // 'timeout' | 'interval'
repeat = 1,
group = 'default',
priority = 0,
name = null,
context = null,
args = []
} = options;
const id = ++this.globalId;
const timer = {
id,
callback,
delay,
type,
repeat,
group,
priority,
name,
context,
args,
createdAt: Date.now(),
executedCount: 0,
lastExecuted: null,
nativeId: null,
paused: false
};
this.timers.set(id, timer);
this.addToGroup(group, id);
this.statistics.created++;
if (!this.paused) {
this.startTimer(timer);
}
return id;
}
// 启动定时器
startTimer(timer) {
const execute = () => {
if (timer.paused || this.paused) return;
try {
if (timer.context) {
timer.callback.apply(timer.context, timer.args);
} else {
timer.callback(...timer.args);
}
timer.executedCount++;
timer.lastExecuted = Date.now();
this.statistics.executed++;
// 检查是否需要继续执行
if (timer.type === 'interval' &&
(timer.repeat === -1 || timer.executedCount < timer.repeat)) {
// 继续执行
} else if (timer.type === 'timeout' ||
timer.executedCount >= timer.repeat) {
// 清理定时器
this.clear(timer.id);
}
} catch (error) {
console.error(`定时器 ${timer.id} 执行错误:`, error);
this.clear(timer.id);
}
};
if (timer.type === 'timeout') {
timer.nativeId = setTimeout(execute, timer.delay);
} else {
timer.nativeId = setInterval(execute, timer.delay);
}
}
// 清理定时器
clear(id) {
const timer = this.timers.get(id);
if (!timer) return false;
if (timer.nativeId) {
if (timer.type === 'timeout') {
clearTimeout(timer.nativeId);
} else {
clearInterval(timer.nativeId);
}
}
this.timers.delete(id);
this.removeFromGroup(timer.group, id);
this.statistics.cleared++;
return true;
}
// 暂停定时器
pause(id) {
const timer = this.timers.get(id);
if (timer && !timer.paused) {
if (timer.nativeId) {
if (timer.type === 'timeout') {
clearTimeout(timer.nativeId);
} else {
clearInterval(timer.nativeId);
}
timer.nativeId = null;
}
timer.paused = true;
return true;
}
return false;
}
// 恢复定时器
resume(id) {
const timer = this.timers.get(id);
if (timer && timer.paused) {
timer.paused = false;
if (!this.paused) {
this.startTimer(timer);
}
return true;
}
return false;
}
// 暂停所有定时器
pauseAll() {
this.paused = true;
for (const timer of this.timers.values()) {
if (timer.nativeId) {
if (timer.type === 'timeout') {
clearTimeout(timer.nativeId);
} else {
clearInterval(timer.nativeId);
}
timer.nativeId = null;
}
}
}
// 恢复所有定时器
resumeAll() {
this.paused = false;
for (const timer of this.timers.values()) {
if (!timer.paused) {
this.startTimer(timer);
}
}
}
// 按组管理
addToGroup(groupName, timerId) {
if (!this.groups.has(groupName)) {
this.groups.set(groupName, new Set());
}
this.groups.get(groupName).add(timerId);
}
removeFromGroup(groupName, timerId) {
const group = this.groups.get(groupName);
if (group) {
group.delete(timerId);
if (group.size === 0) {
this.groups.delete(groupName);
}
}
}
// 清理组
clearGroup(groupName) {
const group = this.groups.get(groupName);
if (group) {
for (const timerId of group) {
this.clear(timerId);
}
}
}
// 获取统计信息
getStatistics() {
return {
...this.statistics,
active: this.timers.size,
groups: this.groups.size,
paused: this.paused
};
}
// 获取定时器信息
getTimerInfo(id) {
const timer = this.timers.get(id);
if (!timer) return null;
return {
id: timer.id,
name: timer.name,
type: timer.type,
delay: timer.delay,
repeat: timer.repeat,
group: timer.group,
priority: timer.priority,
executedCount: timer.executedCount,
paused: timer.paused,
age: Date.now() - timer.createdAt,
lastExecuted: timer.lastExecuted
};
}
// 获取所有定时器信息
getAllTimers() {
return Array.from(this.timers.keys()).map(id => this.getTimerInfo(id));
}
// 清理所有定时器
clearAll() {
for (const id of this.timers.keys()) {
this.clear(id);
}
}
// 销毁调度器
destroy() {
this.clearAll();
this.groups.clear();
this.statistics = { created: 0, executed: 0, cleared: 0 };
}
}
// 使用高级定时器调度系统
const scheduler = new AdvancedTimerScheduler();
// 创建不同类型的定时器
const timer1 = scheduler.schedule(
() => console.log('延迟执行任务'),
1000,
{ name: '延迟任务', group: 'ui' }
);
const timer2 = scheduler.schedule(
(count) => console.log(`周期任务执行第 ${count} 次`),
2000,
{
type: 'interval',
repeat: 5,
name: '周期任务',
group: 'background',
args: [1]
}
);
// 监控统计信息
setInterval(() => {
console.log('调度器统计:', scheduler.getStatistics());
}, 3000);
// 5秒后暂停所有定时器
setTimeout(() => {
scheduler.pauseAll();
console.log('所有定时器已暂停');
}, 5000);
// 8秒后恢复所有定时器
setTimeout(() => {
scheduler.resumeAll();
console.log('所有定时器已恢复');
}, 8000);
// 15秒后清理所有定时器
setTimeout(() => {
scheduler.clearAll();
console.log('所有定时器已清理');
console.log('最终统计:', scheduler.getStatistics());
}, 15000);"掌握定时器机制,让你的JavaScript应用拥有精确的时间控制能力!这是异步编程和性能优化的重要基础。"