记一次使用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' });

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

相关推荐
lichenyang45316 小时前
Docker 学习笔记(一):为什么需要镜像、容器和仓库?
前端
kyriewen17 小时前
别再对着 TypeScript 报错发呆了:我把 10 个最常见的红色波浪线翻译成了人话
前端·javascript·typescript
IT_陈寒17 小时前
SpringBoot自动配置的坑,我的API突然就404了
前端·人工智能·后端
free3517 小时前
从 0 实现一个 Tiny JavaScript VM:项目架构拆解
javascript
奇奇怪怪的17 小时前
Embedding 模型 10+ 横向评测
前端
陈广亮18 小时前
Monorepo 从 0 到 1 实操指南 2026 版:pnpm catalogs + Turborepo 2.x + changesets 全链路
前端
子兮曰18 小时前
OpenMontage 深度解剖:你的 AI 编程助手,其实是个视频工作室
前端·后端·ai编程
敲代码的鱼18 小时前
PDF 预览与签名批注写回 支持安卓 iOS 鸿蒙 UTS插件
android·前端·ios
子兮曰18 小时前
前端工具链的「Rust 化」:一场没有赢家的军备竞赛?
前端·后端·rust