美文网首页
太奇怪了!为什么我的计时器出了这么大误差...崩溃中

太奇怪了!为什么我的计时器出了这么大误差...崩溃中

作者: 拜仁的月饼 | 来源:发表于2023-12-01 12:18 被阅读0次

引言:计时器的困惑

PM:嘿,你来看一下这个倒计时组件,为什么时间总是跳得这么不准确?我们的用户可是每一秒都在盯着看呢!

FE:嗯,这个问题我也注意到了。我猜想可能是因为JavaScript的定时器不够精确所导致的。你知道的,JavaScript的定时器并不是真正的实时。

PM:不是实时?那我们的促销活动岂不是要泡汤了?用户体验可不能因为这个而受到影响啊!

FE:放心吧,我知道这很重要。我会深入调查具体原因,并找到一个解决方案的。我们的倒计时组件会准时如一,准确无误!

PM:那就拜托了!我可不想看到用户因为这个小bug而离我们而去。

所以,让我们揭开这个“时间误差”的谜团,并确保我们的倒计时组件能够精准无误地帮助用户倒数每一秒!

正文:倒计时组件的误差之谜

当你在开发这个功能时,你可能会首先写出像下面这样的代码:

import { FC, useState, useEffect } from "react";
import "./_style.scss";

/** @description 每秒剩余秒数减1 */
export const CountOne: FC<{
  startTime: number;
}> = (props) => {
  const { startTime } = props;

  const [restSec, setRestSec] = useState(startTime);

  useEffect(() => {
    // 创建一个定时器,每隔1秒执行一次
    const inter = setInterval(() => {
      // 更新restSec状态,每秒减一
      setRestSec(oldVal => oldVal - 1);
    }, 1000);

    return () => {
      clearInterval(inter);
    };
  }, []);

  return (
    <div className="pub-style">
      <p className="pub-style-text">每秒减一方案:</p>
      <p className="pub-style-text">
        <span className="pub-style-text-span">倒计时秒数:</span>
        <span className="pub-style-text-span">{restSec}</span>
      </p>
    </div>
  );
};

每秒剩余秒数减1,这个逻辑看似并无问题。然而,经过一段时间的运行,或者在电脑合盖后再运行,你可能会发现实际值与期望值之间存在较大的偏差。

出大差错了

如图所示,第一种方案即为执行一段时间后上述代码的执行结果。是不是很离谱?

这到底是哪里出了问题呢?于是,我把这段代码拿去询问ChatGPT,给出的回答如下:

  1. JavaScript定时器的不精确性

    • JavaScript中的setTimeoutsetInterval函数并不能保证完全精确的时间间隔,因为它们受到了事件循环的影响。如果页面或者浏览器忙于其他任务,定时器的回调可能会被推迟执行。
  2. 浏览器的最小化或标签页切换

    • 当用户最小化浏览器或切换到其他标签页时,浏览器可能会减慢或暂停定时器的回调,以节省资源。
  3. 页面渲染的性能问题

    • 如果页面存在复杂的DOM操作或者JavaScript执行效率低下,可能会影响倒计时组件的更新频率。

怎么办:倒计时组件的误差之谜与解决策略

当我们尝试用JavaScript来实现倒计时功能时,通常会使用setInterval函数。然而,setInterval函数并不能保证完全精确的时间间隔,因为它的执行受到很多因素的影响,比如页面的渲染速度、浏览器的性能等。

第一种方案:使用Web Workers

Web Workers允许我们在后台线程中运行代码,避免了主线程的拥堵,可以提高定时器的准确性。但是,Web Workers无法访问DOM,因此不适用于需要实时渲染的场景。

第二种方案:时间戳比对

我们可以通过存储一个初始时间戳,并在每次回调中比对当前时间戳,以计算真实经过的时间。这种方法比单纯依赖setInterval的回调更为精确。修改后的代码如下:

import { FC, useState, useEffect } from "react";
import { getUnixTime } from "date-fns";

import "./_style.scss";

/** @description 每秒都用deadline - now */
export const CountUseNow: FC<{
  deadlineTime: number;
}> = (props) => {
  const { deadlineTime } = props;

  const [restSec, setRestSec] = useState(
    deadlineTime - getUnixTime(Date.now())
  );

  useEffect(() => {
    // 每隔1秒(1000毫秒)执行一次
    // setRestSec(deadlineTime - getUnixTime(Date.now()))
    // 操作,使得restSec的值每秒更新一次
    const inter = setInterval(() => {
      setRestSec(() => deadlineTime - getUnixTime(Date.now()));
    }, 1000);

    return () => {
      clearInterval(inter);
    };
  }, []);

  return (
    <div className="pub-style">
      <p className="pub-style-text">每秒都用deadline减now方案:</p>
      <p className="pub-style-text">
        <span className="pub-style-text-span">倒计时秒数:</span>
        <span className="pub-style-text-span">{restSec}</span>
      </p>
    </div>
  );
};

以上代码中,我们使用了getUnixTime函数来获取当前时间的秒级时间戳,然后将其与设定的截止时间进行比对,从而得到剩余时间。

第三种方案:使用requestAnimationFrame

对于需要高频更新的倒计时,我们可以使用requestAnimationFrame。它能保证在每次浏览器重绘之前更新时间,从而提高准确性。但是,在非动画场景下,使用频率较低。

第四种方案:优化页面性能

确保DOM操作和JavaScript执行尽可能高效,以减少对倒计时组件更新的干扰。这需要针对具体的应用场景进行优化,无法作为通用的解决方案。

经过比较,第二种方案修改成本较低且满足预期,更适合在大多数情况下使用。当然,具体选择哪种方案还需要根据实际的应用场景来决定。

结论:追求精准的倒计时

我们探讨了前端开发中倒计时组件出现误差的原因,并提供了几种解决方法。通过这些技术手段,我们可以极大地提高倒计时的准确性,确保用户体验不受影响。现在,我们可以告别那些“崩溃中”的时刻,迎接一个更加精准和可靠的倒计时体验。

致谢

ChatGPT 与 文心一言对本文亦有贡献

相关文章

  • 我太奇怪了

    我太奇怪了 莫名其妙的就吃醋 然后就开始自卑 其实人家也就是顺便发了一个 可我真的太好笑了 人家为什么就能说他少年...

  • 奇怪的世界到现在的世界

    说这个世界吧太神奇了!为什么这么说因为世界太奇怪了!为什么种上种子就可以发芽、为什么太阳每天东升西落,为什么火可以...

  • 太奇怪了

  • 2018-02-04

    今天自己太奇怪了,睡觉

  • 2018-12-10

    美文太奇怪了,落伍了

  • 为什么在意?

    为什么会这么在意他人看法? 真的是太奇怪了! 这个人往往会是谁?利益相关者,比如上级或者老板。或者层级比自己更高级...

  • 饭局的秘密

    饭局的秘密就是我喝大了,信口开河了,这么些年了,居然又找到了当年学校的感觉了,太奇怪了。 偶然的机遇,我约了一个朋...

  • 2018-03-13

    太奇怪了太奇怪了 我这啥性格啊 不开心了不满意了都不会说出来 会自己消化掉 然后很开心的再出现在你面前 然后在心里...

  • 2019-05-07

    5月7号,早上记录 梦到曾总,太奇怪了。

  • 2021-01-18

    我的妈我最近好累,感觉要做的事情太多了。多不可怕,主要是不是自己目标相关的。太奇怪了。 怎么会这么忙,还是感觉不到...

网友评论

      本文标题:太奇怪了!为什么我的计时器出了这么大误差...崩溃中

      本文链接:https://www.haomeiwen.com/subject/rsscgdtx.html