引言
最近写代码时候碰到了一个问题,当我切换页面等一会再回到之前页面,页面中和定时器相关连的逻辑代码存在误差。
原因
在查询资料后了解到是因为浏览器干的,浏览器会对非可见或没有打开的页面进行一定的优化,定时器的放慢也是其中一种,
复现问题
这边我用一个demo来复现问题,建立一个测试模板 在js文件中输入下面代码
var oldVal;
var newVal;
setInterval(function () {
newVal = new Date().getTime();
console.log("hi", newVal - oldVal);
oldVal = newVal;
}, 500);
在f12控制台看到打印的结果基本在500上下,这个时候在浏览器打开新页面过一会在切回去之前页面,会发现有1000出现,表明定时器被优化了。
解决方法
在网上找到了不少方法,我采用的外国老哥方法,我用之前的demo接着写,创建timer-worker.js和worker-timer.js文件,修改测试的js文件。
// timer-worker.js
var intervalIds = {}
self.onmessage = function (e) {
switch (e.data.command) {
case 'interval:start':
var intvalId = setInterval(function () {
postMessage({
message: 'interval:tick',
id: e.data.id,
})
}, e.data.interval)
postMessage({
message: 'interval:started',
id: e.data.id,
})
intervalIds[e.data.id] = intvalId
break
case 'interval:clear':
clearInterval(intervalIds[e.data.id])
postMessage({
message: 'interval:cleared',
id: e.data.id,
})
delete intervalIds[e.data.id]
break
}
}
//worker-timer.js
var worker = new Worker('./timer-worker.js')
var workerTimer = {
id: 0,
callbacks: {},
setInterval: function (cb, interval, context) {
this.id++
var id = this.id
this.callbacks[id] = { fn: cb, context: context }
worker.postMessage({
command: 'interval:start',
interval: interval,
id: id,
})
return id
},
onMessage: function (e) {
switch (e.data.message) {
case 'interval:tick':
var callback = this.callbacks[e.data.id]
if (callback && callback.fn) callback.fn.apply(callback.context)
break
case 'interval:cleared':
delete this.callbacks[e.data.id]
break
}
},
clearInterval: function (id) {
worker.postMessage({ command: 'interval:clear', id: id })
},
}
worker.onmessage = workerTimer.onMessage.bind(workerTimer)
// demo.js
var oldVal
var newVal
workerTimer.setInterval(function () {
newVal =new Date().getTime()
console.log('hi',newVal -oldVal );
oldVal = newVal;
}, 500)
这些都是搬运过来的(不是我写的),结尾附上链接。看了一会好像和 web workers有关系,没深入去了解有空再看看。通过这些操作后再次测试发现定时器正常了。