切换页面JS中的定时器不准

544 阅读2分钟

引言

最近写代码时候碰到了一个问题,当我切换页面等一会再回到之前页面,页面中和定时器相关连的逻辑代码存在误差。

原因

在查询资料后了解到是因为浏览器干的,浏览器会对非可见或没有打开的页面进行一定的优化,定时器的放慢也是其中一种,

复现问题

这边我用一个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有关系,没深入去了解有空再看看。通过这些操作后再次测试发现定时器正常了。

参考文献

  1. 为什么切换(标签页)出去后 其js定时器会变慢?
  2. 外国老哥写的