从计时器失效到判断页面可见性

1,问题 - 计时器失效

问题复现:移动端必现,pc 端和浏览器版本有关(公司电脑必现,家里的没有复现)。

通过 setTimeoutsetInterval 实现的倒计时,会在页面隐藏后,实测会延缓计时或经过15s 左右会停止计时,导致计时不准确!直到页面再次激活。

2,解决 - 页面可见性判断

可以通过判断页面可见性,计算出经过的隐藏时间来重置倒计时的时间点。

1,页面可见性

无论使用 pc 还是移动端,都会有当前页面被隐藏的情况:

  • 切换 tab 页
  • 浏览器最小化
  • 切换到其他应用
  • 点击链接跳转到其他页面

2,visibilitychange

MDN 参考

document.addEventListener("visibilitychange", () => {
  // 页面可见
  if (document.visibilityState === "visible") {
    console.log("visible");
  } else {
    console.log("hidden");
  }
});

举例:计算隐藏时间

<body>
  <div id="box">100</div>
  <script>
    const box = document.getElementById("box");

    // 初始时间
    let count = 100;
    const inerval = setInterval(() => {
      if (count <= 0) {
        box.innerHTML = "倒计时结束";
        clearInterval(inerval);
        document.removeEventListener("visibilitychange", visibilitychange);
        return;
      }
      box.innerHTML = count--;
    }, 1000);

    let startTime2Hidden = 0; // 页面隐藏瞬间的时间
    let count2Hidden = 0; // 记录页面隐藏瞬间的 count 值
    document.addEventListener("visibilitychange", visibilitychange);

    function visibilitychange() {
      if (document.visibilityState === "visible") {
        const minus = parseInt((new Date().getTime() - startTime2Hidden) / 1000);
        count = count2Hidden - minus; // 正确经过的时间
      } else {
        startTime2Hidden = new Date().getTime();
        count2Hidden = count;
      }
    }
  </script>

visibilitychange 的问题:在 safari 浏览器下,这个事件不总是触发,比较怪异。

3,终极解决方案 - lifecycle

谷歌实验室开源项目,兼容性很好。

使用举例:

<script src="./lifecycle.es5.js"></script>
<script>
  lifecycle.addEventListener("statechange", function (event) {
    console.log(event.oldState, event.newState);
    if (event.oldState == "passive" && event.newState == "hidden") {
       console.log("hidden");
    } else if ((event.oldState == "hidden" && event.newState == "passive") || (event.oldState == "frozen" && event.newState == "active")) {
       console.log("visibile");
    }
  });
</script>

在判断页面隐藏到显示时,实测发现安卓手机表现比较特殊。浏览器切换到后台或是其他APP时,

  • 时间较短时,则状态变化满足 passive --> hiddenhidden --> passive
  • 时间较长(可能几分钟),则状态变化满足 passive --> hiddenfrozen --> active
  • 时间再长一些,浏览器已打开的网页会退出并回到首页。

注:中间还有其他状态变化,这里省略了。上面2组足够判断显示和隐藏了。

3,精准计时

无论使用哪种解决方案,倒计时都不是准确的,因为用户可能会修改本地时间,况且 js 计时本身就不精准。

要实现精准计时,还得靠后端接口返回正确的时间(后端也会做校验)。

以上面这个问题来说,另一种解决方案:在页面激活时再次请求一次倒计时相关的接口,前端重置倒计时时间点。


以上。

  • 29
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

下雪天的夏风

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

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

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

打赏作者

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

抵扣说明:

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

余额充值