setTimeout 和 setInterval。下面将详细解释代码和两种方法的对比。
代码解释
- sleep 函数
复制代码
const sleep = (time) => {
const start = Date.now();
while (Date.now() - start < time) {}
};
这是一个阻塞函数,利用 while 循环和 Date.now() 来模拟暂停(睡眠)的效果。
参数 time 表示需要暂停的毫秒数。
注意:sleep 会阻塞 JavaScript 主线程,所以在调用期间无法处理其他任务,如事件处理、定时器等。
2. 使用 setTimeout 实现倒计时
const countDown = (count) => {
setTimeout(() => {
console.log(count); // 输出当前倒计时数字
count--; // 减少倒计时计数
sleep(500); // 暂停500ms,模拟等待
if (count > 0) { // 如果还有剩余计数,递归调用
countDown(count);
}
}, 1000);
};
countDown(10); // 从10开始倒计时
每次倒计时通过 setTimeout 延迟 1 秒执行,打印当前计数后调用递归。
sleep(500) 模拟额外的 500ms 暂停,这会进一步延迟下一个倒计时的执行。
问题:
sleep 会阻塞主线程,影响 setTimeout 的精度。
实际的倒计时间会比预期更长,因为 sleep 的 500ms 阻塞叠加在 setTimeout 的 1000ms 延迟之上。
3. 使用 setInterval 实现倒计时
const countDown = (count) => {
const intervalId = setInterval(() => {
console.log(count); // 输出当前倒计时数字
count--; // 减少倒计时计数
sleep(500); // 暂停500ms,模拟等待
if (count <= 0) { // 当计数到0时,清除定时器
clearInterval(intervalId);
}
}, 1000);
};
countDown(10); // 从10开始倒计时
每次倒计时通过 setInterval 周期性执行,间隔设置为 1000ms。
如果倒计时结束(count <= 0),调用 clearInterval 停止定时器。
问题:
同样由于 sleep 的阻塞,会影响后续的 setInterval 调用,导致实际间隔时间大于 1 秒。
setTimeout 与 setInterval 的比较
特性 | setTimeout | setInterval |
---|---|---|
调用方式 | 每次调用后手动递归,产生链式调用。 | 自动周期性调用。 |
精度 | 每次调用都可能因为阻塞或其他代码延迟。 | 受阻塞和延迟的叠加影响更大。 |
灵活性 | 可以在每次递归中调整逻辑和间隔时间。 | 一旦启动,间隔时间固定,灵活性较低。 |
对阻塞的敏感性 | 比较敏感,容易累积延迟。 | 极为敏感,阻塞直接破坏周期性调用。 |
为什么 setInterval 更准确
在这段代码中,setInterval 并不一定更准确,因为它同样受阻塞影响(sleep(500) 会导致周期时间延长)。
如果去掉 sleep(500):
setTimeout 的递归:
每次递归触发一个新的定时器,可以动态调整时间间隔。
但如果递归逻辑复杂,可能产生累积延迟。
setInterval 的周期性:
固定周期执行,理论上更准确。
如果某次回调执行时间较长(如使用阻塞操作),后续调用会被拖延或直接错过。
改进代码
要提高倒计时的精度,可以避免使用阻塞代码(如 sleep),并使用更精准的时间计算。
const countDown = (count) => {
const startTime = Date.now(); // 记录开始时间
const intervalId = setInterval(() => {
const elapsedTime = Date.now() - startTime; // 计算经过的时间
const remaining = Math.max(0, count - Math.floor(elapsedTime / 1000)); // 剩余倒计时
console.log(remaining);
if (remaining <= 0) {
clearInterval(intervalId); // 结束倒计时
}
}, 100); // 更频繁地检查时间,提高精度
};
countDown(10);
通过计算实际经过的时间来动态调整倒计时,避免阻塞操作的影响。
适用于需要更高精度的场景。
以上就是文章全部内容了,如果喜欢这篇文章的话,还希望三连支持一下,感谢!