解决setInterval计时器不准的问题

本文探讨了在JavaScript中使用setInterval进行倒数和计时功能时存在的准确性问题,并提出了一种通过实时修正触发延迟的方法来提高计时精度。通过分析代码示例,展示了如何通过减去当前时间和准确时间的差距来计算下次触发的时间,从而减少误差积累。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在js中如果打算使用setInterval进行倒数,计时等功能,往往是不准确的,因为setInterval的回调函数并不是到时后立即执行,而是等系统计算资源空闲下来后才会执行.而下一次触发时间则是在setInterval回调函数执行完毕之后才开始计时,所以如果setInterval内执行的计算过于耗时,或者有其他耗时任务在执行,setInterval的计时会越来越不准,延迟很厉害.

下面的代码可以说明这个问题

1
2
3
4
5
6
7
8
9
10
11
var startTime = new Date().getTime();
var count = 0;
//耗时任务
setInterval(function(){
    var i = 0;
    while(i++ < 100000000);
}, 0);
setInterval(function(){
    count++;
    console.log(new Date().getTime() - (startTime + count * 1000));
}, 1000);

代码里输出了setInterval触发时间和应该正确触发时间的延迟毫秒数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
176
340
495
652
807
961
1114
1268
1425
1579
1734
1888
2048
2201
2357
2521
2679
2834
2996
......

可以看到延迟是越来越严重的.

为了在js里可以使用相对准确的计时功能,我们可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var startTime = new Date().getTime();
var count = 0;
setInterval(function(){
    var i = 0;
    while(i++ < 100000000);
}, 0);
function fixed() {
    count++;
    var offset = new Date().getTime() - (startTime + count * 1000);
    var nextTime = 1000 - offset;
    if (nextTime < 0) nextTime = 0;
    setTimeout(fixed, nextTime);
     
    console.log(new Date().getTime() - (startTime + count * 1000));
}
setTimeout(fixed, 1000);

代码里,通过1000(也就是周期时间)减去当前时间和准确时间的差距,来算出下次触发的时间,从而修正了当前触发的延迟.

下面是输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
186
200
230
271
158
899
900
899
900
899
899
899
902
899
418
202
232
266
145
174
192
214
242
268
149
179
214
......

可以看到虽然触发时间并非绝对准确,但由于每次触发都进行及时修正,所以并没有造成误差积累.

### Vue 中重置 `setInterval` 计时器的方法 在 Vue.js 开发中,如果需要实现一个可以被正确重置的 `setInterval` 定时器功能,可以通过清除旧的定时器并重新创建一个新的来完成此操作。以下是具体方法: #### 清除与重建定时器 为了确保会存在多个重复运行的定时器实例,在每次启动新的 `setInterval` 前应先调用 `clearInterval(this.timer)` 来清理之前的定时器。 ```javascript export default { data() { return { countDownTime: 10, // 初始倒计时秒数 timer: null // 存储定时器ID }; }, methods: { startTimer() { if (this.timer) { clearInterval(this.timer); // 如果已有timer,则先清空它 } this.countDownTime = 10; // 将倒计时恢复到初始状态 this.timer = setInterval(() => { if (this.countDownTime > 0) { this.countDownTime--; } else { clearInterval(this.timer); } }, 1000); }, resetTimer() { if (this.timer) { clearInterval(this.timer); // 清理当前正在执行的定时器 this.timer = null; } this.startTimer(); // 调用startTimer初始化新定时器 } }, beforeDestroy() { if (this.timer) { clearInterval(this.timer); // 组件销毁前务必清理定时器以防内存泄漏 } } }; ``` 以上代码展示了如何通过定义两个方法——`startTimer()` 和 `resetTimer()` ——分别用于开启和重启定时器的功能[^2]。当用户触发某个事件(比如点击按钮),就可以调用这些方法来进行相应的逻辑处理。 另外需要注意的是,在组件生命周期结束之前一定要记得停止所有的异步任务,这里指的就是要关闭掉由 `setInterval` 创建的任务队列中的循环动作,防止造成必要的性能消耗或者潜在错误行为发生。 最后强调一点关于响应式的属性绑定问题:由于 JavaScript 的特性决定了直接修改对象内部数值可能无法及时通知视图层更新显示内容;因此建议始终遵循 Vue 提供的最佳实践方式去管理数据变化过程中的同步机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值