预设条件
- 静默时长:10分钟;
- 页面失效,返回首页;
- 10分钟内有操作,则重新计时;
- 同一表单页,仅支持唯一一方操作,其他方预操作
实现思路
10分钟的统计通常情况下会使用setInterval()
,但是由于setInterval()
计时会有一定误差,设置在浏览器处于非激活状态下可能会以极慢的速度工作甚至停止计时,因此,本文采用web worker
新建线程来准确计时。
Web Worker
Web Worker:HTML5标准的一部分,允许我们在js主线程之外开辟新的一个线程,并且将一段js脚本运行其中,使其与主线程同步进行,互不阻塞。所以,目前很多在js主线程只专注处理业务逻辑,Worker线程负责计算等复杂任务,提高运行效率、页面流畅度等。
注意
-
Worker 线程中不可操作DOM对象、不可访问window对象;
-
Worker 的顶层对象:
self
-
使用:
new Worker(path, options)
path
:有效的js脚本地址(遵守同源策略)
-
关闭Worker :
worker.terminate()
-
postMessage()
传递的数据支持:由结构化克隆算法处理的任何值或JS对象,包括循环引用。
实现方法
- public 文件夹下,新建Worker.js文件
js
// 监听 接收消息
let timer;
self.addEventListener('message', e => { // 接收到消息
console.log(e.data);
let sum = 0;
let msg;
if (e.data === "start") {
// 每分钟 sum 加 1 标识积累了 1 分钟
timer = setInterval(() => {
sum += 1;
msg = {
text: 'editing',
sum
}
// 向主线程发送消息 msg 对象
self.postMessage(msg);
}, 60 * 1000)
} else {
clearInterval(timer);
}
});
// worker内部错误
self.addEventListener('error', err=>{
cosole.log(err)
})
// 消息体无法被反序列化时
self.addEventListener('messageError', err=>{
cosole.log(err)
})
- Vue组件中创建并使用Worker.js
js
<template>
<el-form>
...表单内容
</el-form>
<template>
<script>
export default {
data:_=>({
worker: null
}),
created() {
this.startWorker();
},
activated() {
this.onTimerReset()
},
methods: {
// 开启worker
startWorker() {
// 判断浏览器兼容性
if(typeof Worker !== 'undefind') {
// 创建Worker实例
this.worker = new Worker('./Worker.js');
this.handleWorker()
} else {
console.log('Your browser does not support Web Workers.')
}
},
stopWorker() {
if(this.worker) {
this.worker.terminate();
this.worker = null;
}
},
handleWorker() {
const selfWorker = this.worker
selfWorker.postMessage('start timer')
// 监听 来自 worker的 message 消息
selfWorker.onmessage = e => {
this.handleWorkerMsg(e.dada)
}
},
// 开启计时
onTimerSatrt() {
this.worker.postMessage('start timer')
},
// 关闭计时
onTimerEnd() {
this.worker.postMessage('start end')
},
// 重新计时
onTimerReset() {
this.onTimerEnd()
this.onTimerSatrt()
},
// 处理数据
handleWorkerMsg(data) {
console.log(data); // {text: 'editing', sum: sum}
campaignListLock(); // 发起续租请求
if(data.sum >10) {
this.onTimerEnd();
if (document.visibilityState === "visible") {
message.error("页面已失效");
pageGoBack();
// 触发了提示就禁止它后续再触发
timeCount = 1;
}
document.addEventListener("visibilitychange", function () {
if (document.visibilityState == "visible" && timeCount == 0) {
message.error("页面已失效");
pageGoBack();
// 触发了提示就禁止它后续再触发
timeCount = 1;
}
});
}
},
},
beforeDestroy() {
// 在组件销毁前停止 Worker,避免内存泄漏
this.stopWorker();
},
}
</script>