您现在的位置是:网站首页 > 定时器与延时器文章详情
定时器与延时器
陈川
【
JavaScript
】
30138人已围观
4889字
在JavaScript中,定时器和延时器是控制代码执行时间的重要工具。它们允许开发者在特定时间间隔或延迟后执行函数,从而实现动画、轮询、异步操作等场景。
setTimeout:延时执行
setTimeout
用于在指定的毫秒数后执行一次函数。它的基本语法如下:
setTimeout(function, delay, [arg1], [arg2], ...);
function
:要执行的函数delay
:延迟的毫秒数arg1, arg2,...
:可选参数,会传递给回调函数
示例1:简单延时
setTimeout(() => {
console.log('这条消息将在3秒后显示');
}, 3000);
示例2:带参数的延时
function greet(name) {
console.log(`Hello, ${name}!`);
}
setTimeout(greet, 2000, 'Alice');
setTimeout
返回一个定时器ID,可以用于取消这个延时:
const timerId = setTimeout(() => console.log('不会执行'), 1000);
clearTimeout(timerId);
setInterval:定时重复执行
setInterval
会按照固定的时间间隔重复执行函数:
setInterval(function, interval, [arg1], [arg2], ...);
示例:每秒更新计数器
let count = 0;
const intervalId = setInterval(() => {
count++;
console.log(`计数: ${count}`);
if (count >= 5) {
clearInterval(intervalId);
}
}, 1000);
定时器的执行机制
JavaScript是单线程的,定时器的回调函数会被放入事件队列,只有当主线程空闲时才会执行。这意味着:
- 定时器的延迟时间是至少等待时间,不一定是精确时间
- 长时间运行的代码会延迟定时器的执行
示例:
console.log('开始');
setTimeout(() => console.log('定时器'), 0);
console.log('结束');
// 输出顺序:
// 开始
// 结束
// 定时器
递归setTimeout vs setInterval
对于需要固定间隔执行的任务,有两种实现方式:
方法1:使用setInterval
setInterval(() => {
console.log('每1秒执行一次');
}, 1000);
方法2:递归使用setTimeout
function repeat() {
console.log('每1秒执行一次');
setTimeout(repeat, 1000);
}
setTimeout(repeat, 1000);
递归setTimeout的优势:
- 可以确保每次执行之间的间隔
- 更容易根据条件停止
- 可以动态调整下一次执行的时间
定时器的实际应用
实现倒计时功能
function countdown(seconds) {
let remaining = seconds;
const timer = setInterval(() => {
console.log(`${remaining}秒...`);
remaining--;
if (remaining < 0) {
clearInterval(timer);
console.log('时间到!');
}
}, 1000);
}
countdown(5);
实现简单的动画效果
const box = document.createElement('div');
box.style.width = '100px';
box.style.height = '100px';
box.style.backgroundColor = 'red';
document.body.appendChild(box);
let position = 0;
const animate = setInterval(() => {
position += 5;
box.style.transform = `translateX(${position}px)`;
if (position > 300) {
clearInterval(animate);
}
}, 50);
实现轮询检查
function checkStatus() {
fetch('/api/status')
.then(response => response.json())
.then(data => {
if (data.ready) {
console.log('任务完成');
} else {
setTimeout(checkStatus, 1000); // 1秒后再次检查
}
});
}
checkStatus();
定时器的高级用法
使用requestAnimationFrame实现动画
对于需要高性能动画的场景,requestAnimationFrame
比setInterval
更合适:
function animate() {
// 动画逻辑
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
使用Promise封装定时器
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function demo() {
console.log('开始等待');
await delay(2000);
console.log('2秒后');
}
demo();
防抖(debounce)实现
function debounce(func, wait) {
let timeout;
return function() {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, arguments);
}, wait);
};
}
// 使用示例
window.addEventListener('resize', debounce(() => {
console.log('窗口大小改变');
}, 300));
节流(throttle)实现
function throttle(func, limit) {
let inThrottle;
return function() {
if (!inThrottle) {
func.apply(this, arguments);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// 使用示例
window.addEventListener('scroll', throttle(() => {
console.log('滚动事件');
}, 1000));
定时器的注意事项
-
内存泄漏:忘记清除定时器可能导致内存泄漏
// 错误示例 function startTimer() { setInterval(() => { console.log('内存泄漏风险'); }, 1000); }
-
this绑定:定时器回调中的this可能不是预期的对象
const obj = { value: 42, showValue: function() { setTimeout(function() { console.log(this.value); // undefined }, 100); } };
解决方法:
// 使用箭头函数 const obj = { value: 42, showValue: function() { setTimeout(() => { console.log(this.value); // 42 }, 100); } };
-
最小延迟限制:浏览器对嵌套定时器有最小延迟限制(通常4ms)
-
后台标签页限制:浏览器可能会降低后台标签页中定时器的执行频率
定时器的替代方案
对于复杂的时间控制需求,可以考虑:
- Web Workers:在后台线程执行定时任务
- requestAnimationFrame:更适合动画场景
- RxJS等响应式编程库提供更强大的时间控制能力
性能优化建议
- 避免在热代码路径中频繁创建和销毁定时器
- 多个定时器可以合并为一个
- 使用
performance.now()
获取高精度时间戳 - 对于不需要精确计时的场景,可以适当增加间隔时间
// 性能优化示例
const startTime = performance.now();
let lastUpdate = startTime;
function update(currentTime) {
const delta = currentTime - lastUpdate;
if (delta > 1000/60) { // 约60FPS
// 执行更新逻辑
lastUpdate = currentTime;
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
上一篇: history对象控制
下一篇: 时间序列数据处理