js准确倒计时

js准确倒计时

引入

如果用最初始的setTimeout递归实现定时器,一秒执行一次回调,则代码如下

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
// 模拟执行大量代码
setInterval(() => {
let i = 0;
while (i++ < 100000000) {
}
}, 0);

function countDown (fn, time) {
let startTime = new Date().getTime(), count = 0, second = 1000;
let timeCounter = null;

return function interFunc () {
let offset = new Date().getTime() - (startTime + count * second);
console.log("误差:" + offset + "ms,下一次执行:" + 1000 + "ms后,离活动开始还有:" + time + "ms");
time -= second;
count++;
if (time < 0) {
clearTimeout(timeCounter);
} else {
timeCounter = setTimeout(() => {
fn.apply(this, arguments);
interFunc();
}, 1000);
}
}
}

countDown(function () {}, 10000)(); // 测试代码

image-20210524235731030

可以看到误差是会越来越多的。

解决

核心思想就是通过计算 当前时间 - 应该到的时间 计算出时间偏移量下一次延迟时间就是 1s - 偏移量

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
29
30
31
32
33
// 模拟执行大量代码
setInterval(() => {
let i = 0;
while (i++ < 100000000) {
}
}, 0);

// 倒计时
function countDown (fn, time) {
let startTime = new Date().getTime(), count = 0, second = 1000;
let timeCounter = null;

return function interFunc () {
let offset = new Date().getTime() - (startTime + count * second);
let nextTime = second - offset;
if (nextTime < 0) {
nextTime = 0
}
console.log("误差:" + offset + "ms,下一次执行:" + nextTime + "ms后,离活动开始还有:" + time + "ms");
time -= second;
count++;
if (time < 0) {
clearTimeout(timeCounter);
} else {
timeCounter = setTimeout(() => {
fn.apply(this, arguments);
interFunc();
}, nextTime);
}
}
}

countDown(function () {}, 10000)(); // 测试代码

image-20210525000118726

可以看到虽然仍有误差,但不会随着时间增大

作者

Liang

发布于

2021-05-25

更新于

2021-12-24

许可协议


评论