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

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

相关推荐
阿蒙Amon1 分钟前
JavaScript学习笔记:17.闭包
javascript·笔记·学习
elangyipi1231 分钟前
深入理解前端项目中的 package.json 和 package-lock.json
前端·json
Wpa.wk3 分钟前
自动化测试 - 文件上传 和 弹窗处理
开发语言·javascript·自动化测试·经验分享·爬虫·python·selenium
l1t5 分钟前
利用小米mimo为精确覆盖矩形问题C程序添加打乱函数求出更大的解
c语言·开发语言·javascript·人工智能·算法
LYFlied13 分钟前
【算法解题模板】-【回溯】----“试错式”问题解决利器
前端·数据结构·算法·leetcode·面试·职场和发展
composurext14 分钟前
录音切片上传
前端·javascript·css
程序员小寒14 分钟前
前端高频面试题:深拷贝和浅拷贝的区别?
前端·javascript·面试
狮子座的男孩19 分钟前
html+css基础:07、css2的复合选择器_伪类选择器(概念、动态伪类、结构伪类(核心)、否定伪类、UI伪类、目标伪类、语言伪类)及伪元素选择器
前端·css·经验分享·html·伪类选择器·伪元素选择器·结构伪类
zhougl99620 分钟前
Vue 中的 `render` 函数
前端·javascript·vue.js
听风吟丶21 分钟前
Spring Boot 自动配置深度解析:原理、实战与源码追踪
前端·bootstrap·html