setTimeout 和 setInterval中使用睡眠函数的对比

setTimeout 和 setInterval。下面将详细解释代码和两种方法的对比。

代码解释

  1. 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 的比较

特性setTimeoutsetInterval
调用方式每次调用后手动递归,产生链式调用。自动周期性调用。
精度每次调用都可能因为阻塞或其他代码延迟。受阻塞和延迟的叠加影响更大。
灵活性可以在每次递归中调整逻辑和间隔时间。一旦启动,间隔时间固定,灵活性较低。
对阻塞的敏感性比较敏感,容易累积延迟。极为敏感,阻塞直接破坏周期性调用。

为什么 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);

通过计算实际经过的时间来动态调整倒计时,避免阻塞操作的影响。
适用于需要更高精度的场景。

以上就是文章全部内容了,如果喜欢这篇文章的话,还希望三连支持一下,感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小纯洁w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值