问题:
切换 tabs 到后台、最小化浏览器,定时器变慢
原因:
浏览器的 Timer throttling 策略:为了提高性能和电池寿命、减少资源的占用,Chrome 浏览器对于未激活的标签页,定时器的最小间隔时间会变为每秒不超过一次。Chrome 88 后更新了更为激进的省电策略,导致后台非活动页面中 setInterval、setTimeout 回调的执行间隔拉长到 1 分钟以上。
解决方法:
- 使用 Web Worker
- HackTimer:基于 Web Worker,模拟 settimeout、setInterval
- 监听 visibilitychange,判断 tab 是否隐藏,记录失活时间后更新,频繁切换会丢失精度。线上 demo:标签未激活状态 setInterval/setTimeout 出现变慢问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| // html 部分 <span>本站已安全运行:</span> <span id="timeDate">载入天数...</span> <span id="times">载入时分秒...</span> // js 部分 <script> let count = 0 let now = new Date(); let addDate = new Date(count) function createtime() { let grt = new Date("2021-05-28 22:10:58"); if(count>0){ now.setTime(now.getTime() + count + 250); count = 0 }else{ now.setTime(now.getTime() + 250); } days = (now - grt) / 1000 / 60 / 60 / 24; dnum = Math.floor(days); hours = (now - grt) / 1000 / 60 / 60 - (24 * dnum); hnum = Math.floor(hours); if (String(hnum).length == 1) { hnum = "0" + hnum; } minutes = (now - grt) / 1000 / 60 - (24 * 60 * dnum) - (60 * hnum); mnum = Math.floor(minutes); if (String(mnum).length == 1) { mnum = "0" + mnum; } seconds = (now - grt) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum); snum = Math.round(seconds); if (String(snum).length == 1) { snum = "0" + snum; } document.getElementById("timeDate").innerHTML = dnum + " 天 "; document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒"; }
let timer = setInterval("createtime()", 250);
function handleVisibilityChange() { if (document.visibilityState == 'hidden') { console.log('visibilitychange - hidden'); clearInterval(timer); start = new Date().getTime(); } else if (document.visibilityState == 'visible') { end = new Date().getTime(); count = end - start timer = setInterval("createtime()", 250); console.log('visibilitychange - visible',start,end); } }
document.addEventListener('visibilitychange', handleVisibilityChange); </script>
|
参考文章:
Web Worker
Timer throttling 策略
chrome57 - backgroundTabs
Heavy throttling of chained JS timers beginning in Chrome 88