浏览器切换到其他标签页或最小化js定时器是否准时测试

目录
  • 前言
  • 浏览器可见和不可见状态
  • setInterval
  • setTimeout
  • requestAnimationFrame
  • 总结
  • 如何解决

前言

这是我最近开发碰到的一个问题,本文是我测试出来的实践结果,供大家参考。

关于js定时器,setInterval和setTimeout,作为我们日常开发经常使用到的方法,大家一定非常熟悉。比如下面一个例子:

setInterval(() => {
  console.log('1');
}, 500);

作为刚学前端没多久的新人也能知道,这段代码就是每过500ms打印一次1(实际运行还需要考虑js的宏任务和微任务的执行时间,定时器的间隔时间是500ms,但是定时器中的方法触发可能需要在宏任务队列中排队,不一定会在500ms的时候触发,关于Event Loop的基础内容不在本文讨论之内)。

但是如果你把浏览器从当前页面切换到另一个标签页,或者把浏览器最小化了,这时候,这个页面定时器的间隔时间还是500ms

本文将测试setInterval、setTimeout、requestAnimationFrame这三个方法在浏览器可见以及不可见状态下的表现,我的测试浏览器以及版本是谷歌(86.0.4240.193),火狐(81.0.2),ie11。

浏览器可见和不可见状态

浏览器的可见和不可见状态的切换会触发visibilitychange事件,我们可以通过监听这个事件来判别浏览器的可见状态。

document.addEventListener("visibilitychange", function() {
  console.log(document.visibilityState);
});

document.visibilityState有三个值

  • hidden:页面彻底不可见。
  • visible:页面至少一部分可见。
  • prerender:页面即将或正在渲染,处于不可见状态。 这里重点关注hidden这个值,当我们浏览器切换当前页面到另外一个标签页或者把浏览器最小化的时候,document.visibilityState就会是hidden值。我们也可以使用document.hidden,它返回一个布尔值,为true的时候,说明当前浏览器是不可见状态。

关于visibilitychange的细节可以看阮一峰老师的这篇文章 Page Visibility API 教程。

setInterval

我们先来测试setInterval,代码如下

<button id="btn">开始计时</button>
// 兼容ie写法
document.getElementById('btn').addEventListener('click', function() {
  setInterval(function() {
    const myDate = new Date();
    const currentDate = myDate.getMinutes() + '分'+ myDate.getSeconds() + '秒' + myDate.getMilliseconds() + '豪秒';
    // 每次循环打印当前时间
    console.log(currentDate);
  }, 500);
});
// 浏览器可见状态切换事件
document.addEventListener('visibilitychange', function() {
  if(document.hidden) {
    console.log('页面不可见');
  }
});

定时器间隔是500ms,先来看下谷歌浏览器

我们发现,当页面不可见之后,定时器的间隔变成了1s。 接下来,我们把定时器间隔改成2s来试下。

前后间隔时间一致。

接下来测试一下火狐和ie。这里列出的图片都是500ms和2s的例子。

ie浏览器

经过我大量的测试,可以得出结论,谷歌浏览器中,当页面处于不可见状态时,setInterval的最小间隔时间会被限制为1s。火狐浏览器的setInterval和谷歌特性一致,但是ie浏览器没有对不可见状态时的setInterval进行性能优化,不可见前后间隔时间不变

setTimeout

接下来是setTimeout

function timer() {
  setTimeout(function() {
    const myDate = new Date();
    const currentDate = myDate.getMinutes() + '分'+ myDate.getSeconds() + '秒' + myDate.getMilliseconds() + '豪秒';
    console.log(currentDate);
    timer();
  }, 500)
}
// 兼容ie写法
document.getElementById('btn').addEventListener('click', function() {
  timer();
});

同样先来看看在谷歌浏览器中的表现(还是500ms和2s)

我们发现在谷歌浏览器中,500ms的间隔,setTimeout和setInterval表现一致,都是最小间隔限制为1s。但是2s隔间的测试结果出现了分歧,页面不可见之后,间隔变成了3s。继续经过多次的测试,如下,左图的间隔时间为990ms,右图的间隔时间为1s。

不可见状态下,左图中的990ms间隔时间变为1s,右图中的1s间隔时间变为2s。

我们再来看看火狐(500ms和2s)

火狐浏览器不可见状态下,左图中的500ms变为1s,右图中的2s保持不变。

再来看看ie浏览器(500ms)

一样毫无优化。

我们可以得出结论

  • 在谷歌浏览器中,setTimeout在浏览器不可见状态下间隔低于1s的会变为1s,大于等于1s的会变成N+1s的间隔值。
  • 火狐浏览器下setTimeout的最小间隔时间会变为1s,大于等于1s的间隔不变。ie浏览器在不可见状态前后的间隔时间不变。

requestAnimationFrame

raf是浏览器提供的一个更流畅的处理动画的方法,它会在下次浏览器GUI绘制页面的时候运行传入的方法。GUI绘制页面的频率跟显示器的刷新率有关,普通显示器的刷新率是60hz,因此raf在一秒之内需要运行60次,间隔四舍五入大概是17ms。

function timer() {
  const myDate = new Date();
  const currentDate = myDate.getMinutes() + '分'+ myDate.getSeconds() + '秒' + myDate.getMilliseconds() + '豪秒';
  console.log(currentDate);
  window.requestAnimationFrame(timer)
}
// 兼容ie写法
document.getElementById('btn').addEventListener('click', function() {
  timer();
});

我们来看看不同浏览器下面的表现:

谷歌浏览器

火狐浏览器

ie浏览器

我们可以发现,谷歌浏览器和ie浏览器当浏览器状态为不可见时,raf方法将停止执行。火狐浏览器当状态变为不可见时,会在间隔是1s,2s,4s,8s,16s,32s...这样的顺序下去执行raf方法。

总结

谷歌浏览器中,当页面处于不可见状态时,setInterval的最小间隔时间会被限制为1s。火狐浏览器的setInterval和谷歌特性一致。ie浏览器没有对不可见状态时的setInterval进行性能优化,不可见前后间隔时间不变。

在谷歌浏览器中,setTimeout在浏览器不可见状态下间隔低于1s的会变为1s,大于等于1s的会变成N+1s的间隔值。火狐浏览器下setTimeout的最小间隔时间会变为1s,大于等于1s的间隔不变。ie浏览器在不可见状态前后的间隔时间不变。

谷歌浏览器和ie浏览器当浏览器状态为不可见时,raf方法将停止执行。火狐浏览器当状态变为不可见时,会在间隔是1s,2s,4s,8s,16s,32s...这样的顺序下去执行raf方法。

如何解决

碰到问题当然需要解决,在一些定时器小于1s的倒计时的页面中,如果用户切换到了其他标签页。再切回去的时候,页面上显示的倒计时时间其实是错误的,这种隐藏的bug会带来很大的风险。该怎么解决呢?

除了调取后台接口或者websocket连接之外,其实有一个更好的解决方案,webWorkers。而且webWorkers还可以解决一个页面存在多个定时器时候间隔时间误差较大的问题。

直接上例子

document.getElementById('btn').addEventListener('click', function() {
  var w = new Worker('demo_workers.js');
  w.onmessage = function(event){
    console.log(event.data);
  };
});
//浏览器切换事件
document.addEventListener('visibilitychange', function() {
  if(document.hidden) {
    console.log('页面不可见');
  }
});
// demo_workers.js
setInterval(function() {
  const myDate = new Date();
  const currentDate = myDate.getMinutes() + '分'+ myDate.getSeconds() + '秒' + myDate.getMilliseconds() + '豪秒';
  postMessage(currentDate);
}, 500);

实际结果

间隔保持一致。

以上就是浏览器切换到其他标签页或最小化js定时器是否准时测试的详细内容,更多关于浏览器切换js定时器准时测试的资料请关注我们其它相关文章!

(0)

相关推荐

  • JavaScript定时器原理

    目录 一. setTimeout() 定时器 二.停止 setTimeout() 定时器 三.setInterval() 定时器 四.清除setInterval() 定时器 五.电子时钟案例 前言: 在很多页面中,我们都可以看到一些倒计时或者和时间相关的效果,今天小熊将就JavaScript里面的倒计时做一概述. 首先,我们先来看看定时器,在JS中,有两种定时器: 一. setTimeout() 定时器 语法: window.setTimeout(调用函数, [延迟的毫秒数]); setTime

  • JS定时器不可靠的原因及解决方案

    目录 前言 定时器工作原理 setInterval调用被废弃 事件循环 导致定时器不可靠的原因 延迟执行时间有最大值 解决方案 总结 前言 在工作中应用定时器的场景非常多,但你会发现有时候定时器好像并没有按照我们的预期去执行,比如我们常遇到的setTimeout(()=>{},0)它有时候并不是按我们预期的立马就执行.想要知道为什么会这样,我们首先需要了解Javascript计时器的工作原理. 定时器工作原理 为了理解计时器的内部工作原理,我们首先需要了解一个非常重要的概念:计时器设定的延时是没

  • 利用JS定时器实现元素移动

    利用JS定时器做一个元素做一个有移动效果的方法,实现思路:首先声明一个变量存放元素距离左侧的边距,然后我们在声明一个变量存放每次元素需要移动的距离,然后再给这个方法一个完成时间就可以了.需要注意的是获取到的值如果不是数值型的数据需要装换,否则不能进行判断.再判断一下该元素移动到某个位置之后,步长给它一个负值,该元素就会往回跑了. 大家还可以想一想元素移动到左右侧的时候如何实现转身效果. <!DOCTYPE html> <html> <head> <meta cha

  • js定时器出现第一次延迟的原因及解决方法

    我们在使用js定时器,经常会出现间隔几秒获取一次数据,这是通过setInterval实现的.而且如果setInterval() 参数传递不当,定时器会延迟试行.本文向大家介绍js定时器第一次延迟的原理及实现过程. setInterval() 作用是在播放动画的时,每隔一定时间就调用函数.方法或对象. 语法 setInterval(function(),time); 单位是毫秒 注意:单位是毫秒 定时器第一次延迟执行:采用setInterval实现 var t = setInterval(scro

  • JavaScript定时器实现限时秒杀功能

    本文实例为大家分享了JavaScript实现限时秒杀功能的具体代码,供大家参考,具体内容如下 文件index.html 代码: <!DOCTYPE html> <html> <head> <meta charset="GBK" /> <title>show</title> <link rel="stylesheet" href="css/index.css" type=

  • js实现0ms延时定时器的几种方式

    目录 queueMicrotask async/await MessageChannel 最后 附录 这两天看到一篇介绍<如何实现准时的 setTimeout?>的文章,文章起源于一道面试题:有什么办法让setTimeout准时呀?具体文章内容可查看附录[1],看完之后,引起了我对setTimeout这个函数的探究兴趣,因此在MDN上重新查阅了相关文档,其中提到[最小延时 >=4ms]的一点,因此使用setTimeout不能实现0ms延时的定时器,如果要实现的话,提供了一个参考链接[2]

  • 浏览器切换到其他标签页或最小化js定时器是否准时测试

    目录 前言 浏览器可见和不可见状态 setInterval setTimeout requestAnimationFrame 总结 如何解决 前言 这是我最近开发碰到的一个问题,本文是我测试出来的实践结果,供大家参考. 关于js定时器,setInterval和setTimeout,作为我们日常开发经常使用到的方法,大家一定非常熟悉.比如下面一个例子: setInterval(() => { console.log('1'); }, 500); 作为刚学前端没多久的新人也能知道,这段代码就是每过5

  • 定时器在页面最小化时不执行实现示例

    目录 引言 useInterval 和 useTimeout setTimeout 和 setInterval 的问题 useRafInterval 和 useRafTimeout setRafInterval clearRafInterval 思考与总结 引言 本文是深入浅出 ahooks 源码系列文章的第七篇,这个系列的目标主要有以下几点: 加深对 React hooks 的理解. 学习如何抽象自定义 hooks.构建属于自己的 React hooks 工具库. 培养阅读学习源码的习惯,工具

  • iOS左右滑动标签页导航的设计

    iOS中左右滑动切换,滑动标签页导航的设计思路,具体内容如下 iOS开发中经常(几乎每个APP都含有这样的页面吧,几乎!UI设计师也都是这样抄来抄去-..) demo见Github:SliderTab 估计很多人都会说,直接用第三方就可以了,很多人封装过,很好用.而且这样的页面用第三方2分钟搞定,省时省力. 笔者也曾用过第三方,但是屡屡出bug.而且不好修改.所以只能自己写,bug少,代码通俗易懂,童叟无欺. 这里介绍一个第三方DLSlideView,Github地址:DLSlideView,目

  • python selenium 对浏览器标签页进行关闭和切换的方法

    1.关闭浏览器全部标签页 driver.quit() 2.关闭当前标签页(从标签页A打开新的标签页B,关闭标签页A) driver.close() 3.关闭当前标签页(从标签页A打开新的标签页B,关闭标签页B) 可利用浏览器自带的快捷方式对打开的标签进行关闭 Firefox自身的快捷键分别为: Ctrl+t 新建tab Ctrl+w 关闭tab Ctrl+Tab /Ctrl+Page_Up 定位当前标签页的下一个标签页 Ctrl+Shift+Tab/Ctrl+Page_Down 定位当前标签页的

  • Python+Selenium实现浏览器标签页的切换

    目录 selenium 实现浏览器标签页句柄的切换 浏览器标签页本地文件准备 利用 selenium 实现浏览器页面的切换 在实际工作中,我们经常会遇到页面切换的情况.就比如当点击了某个功能的按钮后,浏览器出现了新的标签页,需要在这些标签页之间进行切换.要如何通过 selenium 来实现这样的场景呢?这就是我们今天要学习的内容. selenium 实现浏览器标签页句柄的切换 浏览器标签页本地文件准备 这一段纯粹是因为内容太少,拿来凑字数的... 同样的,这里所使用的是我们本地的 multi.h

  • 全面解析标签页的切换方式

    标签页的切换方式如下所示: 1.控制tab的显示与隐藏 2.tab不切换,数据加载 控制tab的显示与隐藏 前端脚本: 1.jquery实现: $(function(){ $(".sdkj-tabs li").click(function() { $(this).addClass("on").siblings().removeClass("on"); var index=$(".sdkj-tabs li").index(thi

  • JS实现仿饿了么在浏览器标签页失去焦点时网页Title改变

    说在前面:必须是基于支持H5的浏览器才可以 这个 API 本身非常简单,由以下三部分组成. document.hidden:表示页面是否隐藏的布尔值.页面隐藏包括 页面在后台标签页中 或者 浏览器最小化 (注意,页面被其他软件遮盖并不算隐藏,比如打开的 sublime 遮住了浏览器). document.visibilityState:表示下面 4 个可能状态的值 hidden:页面在后台标签页中或者浏览器最小化 visible:页面在前台标签页中 prerender:页面在屏幕外执行预渲染处理

  • 详解vue2.0 使用动态组件实现 Tab 标签页切换效果(vue-cli)

    在 vue 中,实现 Tab 切换主要有三种方式:使用动态组件,使用 vue-router 路由,使用第三方插件. 因为这次完成的功能只是简单切换组件,再则觉得使用路由切换需要改变地址略微麻烦,所以使用的是动态组件实现,如果是在大型应用上,可能使用 vue-router 会方便一些. 先看下最终实现的效果,结构比较简单,顶部的三个 Tab 标签用于切换,内容区域分别为三个子组件. 效果预览 关键代码及分析如下: <template> // 每一个 tab 绑定了一个点击事件,传入的参数对应着

  • JS实现标签页切换效果

    本文实例为大家分享了JS标签页切换的具体代码,供大家参考,具体内容如下 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>resize</title> <style type="text/css"> *{margin:0;padding:0;}

  • 最简单纯JavaScript实现Tab标签页切换的方式(推荐)

    先说一下最土的一种方法: Html: <div class="tab-head"> <h2 id="tab1" onmouseover="changeTab1()" class="selected">1</h2> <h2 id="tab2" onmouseover="changeTab2()">2</h2> <h2 id=

随机推荐