一、项目需求:微信公众号嵌入网页应用,应用中存在倒计时功能,当应用被置于后台或息屏状态,定时器被睡眠。
二、基于需求写了网页定时器:this.setInterval = setInterval(() => {},times);
[问题]:应用被挂起,定时器停止;
三、解决方案:
1、JavaScript多线程之HTML5 Web Worker
createWorker(callback, time){ // 创建线程
let create = function(f) {
var blob = new Blob(['(' + f +')()']);
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url);
return worker;
};
var pollingWorker = create(`function (e) {
setInterval(function () {
this.postMessage(null)
}, ${time})
}`);
pollingWorker.onmessage = callback
return pollingWorker;
},
stopWorker(vm){ // 终止线程
try {
vm&&vm.terminate()
} catch (err) {}
},
应用线程,但是在销毁的时候,也要再次销毁线程。
this.interval = this.createWorker(() => {
//做要做的事
this.txt++;
if(this.txt == 30){
this.stopWorker(this.interval)
this.interval = null;
}
}, 1000)
2、 visibilitychange - Web API 接口参考 | MDN
document.addEventListener("visibilitychange", this.checkViChange);
document.removeEventListener("visibilitychange", this.checkViChange);
checkViChange(){
if (document.hidden) { // 隐藏
this.cacheHiddenTime = moment().unix();
if(this.setInterval){
clearInterval(this.setInterval);
this.setInterval = null;
};
}else{
let cur = moment().unix() - this.cacheHiddenTime;
this.countdown = this.countdown>cur ? (this.countdown-cur) : 0;
this.countDownUtil();
}
},
额外/*
* 倒计时秒转换【工具】
* @param {string|0} 秒seconds
*/
momentUtil(seconds) {
let currentTime = moment.duration(seconds, 'seconds');
let ms = moment({
h: currentTime.hours(),
m: currentTime.minutes(),
s: currentTime.seconds()
}).format('mm:ss');
return {
m: ms.includes("Invalid") ? "00" : ms.split(':')[0],
s: ms.includes("Invalid") ? "00" : ms.split(':')[1]
};
}
注意事项:在页面hidden情况下,虽然定时器被浏览器机制暂缓了,但是再次打开定时随便会加快直到恢复定时间隔,而且定时器没被销毁。所以在应用被挂起,最好的方式将定期器清除,再次打开的时候重新创建。本人采用的是visibilitychange方式。