一、定时器类型与属性
方法 | 返回值 | 执行特性 | 清除方法 |
---|---|---|---|
setTimeout() |
唯一ID(整数) | 单次延迟执行 | clearTimeout() |
setInterval() |
唯一ID(整数) | 周期性重复执行 | clearInterval() |
核心属性:
-
最小延迟时间:4ms(HTML5规范要求)
-
ID类型:整数(Node.js返回对象)
-
this绑定:全局对象(非严格模式)/ undefined(严格模式)
二、基本用法与语法
javascript
// setTimeout - 延迟执行
const timeoutID = setTimeout(callback, delay, [arg1], [arg2], ...);
// setInterval - 周期执行
const intervalID = setInterval(callback, interval, [arg1], [arg2], ...);
// 清除定时器
clearTimeout(timeoutID);
clearInterval(intervalID);
参数说明:
-
callback
: 要执行的函数 -
delay/interval
: 毫秒数(实际最小4ms) -
arg1, arg2...
: 传递给回调函数的参数(IE9+)
三、执行机制详解
1.事件循环中的位置:
javascript
console.log("Start");
setTimeout(() => console.log("Timeout"), 0);
console.log("End");
// 输出顺序:
// Start → End → Timeout
-
定时器回调进入任务队列,等待主线程空闲
-
即使延迟为0,也需等待同步代码执行完毕
2. 时间精度问题:
-
浏览器后台标签页:最小间隔1s(节电优化)
-
连续嵌套定时器:实际间隔可能大于设定值
四、关键使用场景
1.用户交互优化:
javascript
// 防抖(resize/input等高频事件)
function debounce(fn, delay) {
let timer;
return function() {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, arguments), delay);
};
}
// 节流(scroll/mousemove)
function throttle(fn, interval) {
let lastTime = 0;
return function() {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, arguments);
lastTime = now;
}
};
}
2.动画与轮询:
javascript
// requestAnimationFrame替代方案
function animate() {
if (!stopAnimation) {
updatePosition();
setTimeout(animate, 16.7); // ~60fps
}
}
// API轮询
function pollServer() {
fetch('/api/data')
.then(handleData)
.finally(() =>
setTimeout(pollServer, 5000) // 5秒后重试
);
}
3.状态延迟处理:
javascript
// Toast自动关闭
function showToast(message) {
displayToast(message);
setTimeout(hideToast, 3000);
}
// 页面超时锁定
let inactivityTimer = setTimeout(lockApp, 600000); // 10分钟
document.addEventListener('mousemove', () => {
clearTimeout(inactivityTimer);
inactivityTimer = setTimeout(lockApp, 600000);
});
五、高级技巧与陷阱
1.闭包内存泄漏:
javascript
// 错误示例
function startTimer() {
const data = largeObject; // 被闭包引用
setInterval(() => {
console.log(data); // data无法释放!
}, 1000);
}
// 解决方案:适时清除
let timer;
function startSafeTimer() {
const data = largeObject;
timer = setInterval(handler, 1000);
function handler() { ... }
}
function stopTimer() {
clearInterval(timer);
}
2.精确时间补偿:
javascript
// 动态调整周期执行
let expected = Date.now() + 100;
function driftCorrection() {
const drift = Date.now() - expected;
processTask();
// 下次执行时间补偿
expected += 100;
setTimeout(driftCorrection, Math.max(0, 100 - drift));
}
3.Promise封装:
javascript
// 定时器Promise化
function wait(delay) {
return new Promise(resolve =>
setTimeout(resolve, delay)
);
}
// 使用示例
async function delayedFetch() {
await wait(1000);
return fetch('/data');
}
六、最佳实践
1.优先选择方案:
- 动画 →
requestAnimationFrame()
- 微任务 →
Promise
/queueMicrotask()
- 宏任务 →
setTimeout()
2.安全清除模式:
javascript
// React组件示例
useEffect(() => {
const timer = setTimeout(() => {}, 1000);
return () => clearTimeout(timer); // 清理函数
}, []);
3.性能优化:
-
避免嵌套深层定时器
-
非活动标签页使用
Page Visibility API
暂停定时器
javascript
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
clearInterval(timer);
} else {
restartTimer();
}
});
总结:定时器选择矩阵
场景 | 推荐方案 | 原因 |
---|---|---|
单次延迟操作 | setTimeout |
精准控制单次执行 |
固定周期任务 | setInterval |
简单周期逻辑 |
UI动画/渲染相关 | requestAnimationFrame |
与刷新率同步,更流畅 |
高频状态更新(如游戏) | requestAnimationFrame |
避免过度渲染 |
Promise链中的延迟 | await wait(ms) |
更好的异步流程控制 |
需要补偿的时间敏感任务 | 递归setTimeout |
动态调整执行间隔 |
掌握定时器的底层机制和适用场景,是构建高性能、响应式前端应用的关键技能。在框架中使用时(如React的useEffect),务必注意内存管理和清理时机。