记一次使用setInterval(),定时器不准的问题

背景

在项目中,使用了setInterval()定时器函数实现一个倒计时的功能,并且倒计时的时长是可变的,当时长设置过大,并且在倒计时的过程中,切换浏览器,或者最小化,当再次返回的时候会出现定时器不准或者卡住的问题;

在网上看了很多文章:

  1. 首先受事件循环机制的原因,定时器设置的delay时间延迟没那么准确,这个还是比较好理解的;
  2. 第二点就是,看到有文章说浏览器tab切换,浏览器为了优化后台tab的加载损耗(以及降低耗电量),在未被激活的tab中定时器的最小延时限制为1S(1000ms),如果延时限制小于1S,也会出现不准的状况,这个我没有去尝试,因为我设置的时间间隔是1S;
  3. 然后就是浏览器最小化或者切换到后台运行时,时间长了之后浏览器的休眠机制,我觉得我的问题大概率就是这个原因造成的;

解决方案

网上提供的一些解决方案:

  1. 使用setTimeout()实现setInterval()的机制,我觉得我的问题点不在这;
  2. requestAnimationFrame,这个以后有时间看一下,目前不太了解;
  3. Web Worker:目前使用的是这种方式;

Web Worker

Web Worker 使得在一个独立于 Web 应用程序主执行线程的后台线程中运行脚本操作成为可能。这样做的好处是可以在独立线程中执行费时的处理任务,使主线程(通常是 UI 线程)的运行不会被阻塞/放慢。

实现一个定时器的基本操作:开启,暂停,重置,清除;并且我们是因为主线程中定时器不准才使用Worker的,所以我觉得重点是在正确的时间点告诉主线程即可,具体主线程要在定时器中做什么,那就让主线程在接受到消息的时候,自己去做就好了;

timeWorker.js:

js 复制代码
// 监听主线程的指令
let intervalId = null; 
let isRunning = false; 
let count = 0; 

let interval = '';
let countDown = 0;
let isRunning = false;
self.onmessage = (e) => {
  switch (e.data.action) {
    case 'start':
      startInterval();
      break;
    case 'pause':
      pauseInterval();
      break;
    case 'stop':
      clearInterval();
      break;
    case 'reset':
      resetInterval();
      break;
  }
};

// 开启
const startInterval = () => {
  if (!interval) {
    isRunning = true;
    interval = setInterval(() => {
      self.postMessage({ msg: '定时器开启~', count });
    }, 1000);
  }
};

// 暂停
const pauseInterval = () => {
  if (isRunning) {
    clearInterval(interval);
    isRunning = false;
  }
};
// 重置
const resetInterval = () => {
  clearInterval(interval);
  isRunning = false;
  count = 0;
  startInterval();
};
// 清除
const clearInterval = () => {
  clearInterval(interval);
  isRunning = false;
  count = 0;
};

主线程中在需要开启对定时器进行操作的地方进行即可;

js 复制代码
const worker = new Worker('./timeWorker.js');
// 接收消息
worker.onmessage = (e) => {
    // ...处理自己的业务逻辑
  console.log(e.data);
};

// 发消息
worker.postMessage({ action: 'start' });

先简单记录一下,以后有时间再详细记录;

相关推荐
庸俗今天不摸鱼13 分钟前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX1873014 分钟前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下20 分钟前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox31 分钟前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞33 分钟前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行34 分钟前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_5937581035 分钟前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox
掘金一周38 分钟前
金石焕新程 >> 瓜分万元现金大奖征文活动即将回归 | 掘金一周 4.3
前端·人工智能·后端
三翼鸟数字化技术团队1 小时前
Vue自定义指令最佳实践教程
前端·vue.js
Jasmin Tin Wei1 小时前
蓝桥杯 web 学海无涯(axios、ecahrts)版本二
前端·蓝桥杯