其实原理就是浏览器切换到后台了,会降低了这两个的频率,省内存嘛,其实从产品角度,这还是没啥问题的,就是坑了前端被!
Worker 解决方案
搜了下,找到了Worker 方法
但是一看,第一个得传url,这传url在传统的里面还行,这特么vue里面怎么整!
看下传统方案
// time-worker.js var intervalIds = {}; // 监听message 开始执行定时器或者销毁 self.onmessage = function(e){ switch(e.data.command){ case 'interval:start': var intervalId = 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] = intervalId; break; case 'timeout:start': var timeoutId = setTimeout(function(){ postMessage({ message: 'timeout:tick', id: e.data.id }) },e.data.timeout); postMessage({ message: 'timeout:started', id: e.data.id }); intervalIds[e.data.id] = timeoutId; break; case 'interval:clear': // 销毁 clearInterval(intervalIds[e.data.id]); postMessage({ message: 'interval:cleared', id: e.data.id }) delete intervalIds[e.data.id]; break; case 'timeout:clear': // 销毁 clearTimeout(intervalIds[e.data.id]); postMessage({ message: 'timeout:cleared', id: e.data.id }) delete intervalIds[e.data.id]; break; } }
// worker.js var worker = new Worker('./time-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; }, setTimeout: function(cb, timeout, context) { this.id++; var id = this.id; this.callbacks[id] = { fn: cb, context: context }; worker.postMessage({ command: 'timeout:start', timeout: timeout, id: id }); return id; }, // 监听worker 里面的定时器发送的message 然后执行回调函数 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 'timeout: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; case 'timeout:cleared': delete this.callbacks[e.data.id]; break; } }, // 往worker里面发送销毁指令 clearInterval: function(id) { worker.postMessage({ command: 'interval:clear', id: id }); }, clearTimeout: function(id) { worker.postMessage({ command: 'timeout:clear', id: id }); } }; worker.onmessage = workerTimer.onMessage.bind(workerTimer);
使用
<!doctype html><html lang="en"><head> <meta charset="UTF-8"> <title>稳定版定时器</title></head><body><div> <p>Times:500ms</p> <p> 开始时间(s):<span id="startTime"></span> ---- 结束时间(s):<span id="endTime"></span> </p> <p id="nums"></p> <button id="btn">开始</button></div><script src="worker-timer.js"></script><script> var nums = document.getElementById('nums'); var btn = document.getElementById('btn'); var startTime = document.getElementById('startTime'); var endTime = document.getElementById('endTime'); var number = 1; var intervalId = null; btn.addEventListener('click',function(e){ if(e.target.innerHTML == '开始'){ startTime.innerHTML = new Date().getSeconds(); intervalId = workerTimer.setInterval(function(){ nums.innerHTML = ++number; },500); e.target.innerHTML = '暂停'; }else{ endTime.innerHTML = new Date().getSeconds(); workerTimer.clearInterval(intervalId); e.target.innerHTML = '开始' } },false);</script></body></html>
vue2方案
1、下组件
cnpm i worker-loader -D
2、配置vue.config.js
在chainWebpack 按顺序添加就行
chainWebpack(config) { config.module .rule('worker') .test(/\.worker\.js$/) .use('worker-loader') .loader('worker-loader') .options({ inline: 'fallback', filename: 'workerName.[hash].worker.js', }) config.output.globalObject('this') // 解决:worker 热更新问题 config.module.rule('js').exclude.add(/\.worker\.js$/); }
这里可能存在部分内容冲突
如我下面这个就冲突了
// 这个不要复制 config.when(process.env.NODE_ENV === 'development', config => config.devtool('cheap-source-map') )
3、utils下新建 web.worker.js 文件
注意下一定要以.worker.js结尾,因为我们配置文件内使用的这个规则,当然你可以自定义
// web.worker.jsvar intervalIds = {};// 监听message 开始执行定时器或者销毁onmessage = function(e){ switch(e.data.command){ case 'interval:start': var intervalId = 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] = intervalId; break; case 'timeout:start': var timeoutId = setTimeout(function(){ postMessage({ message: 'timeout:tick', id: e.data.id }) },e.data.timeout); postMessage({ message: 'timeout:started', id: e.data.id }); intervalIds[e.data.id] = timeoutId; break; case 'interval:clear': // 销毁 clearInterval(intervalIds[e.data.id]); postMessage({ message: 'interval:cleared', id: e.data.id }) delete intervalIds[e.data.id]; break; case 'timeout:clear': // 销毁 clearTimeout(intervalIds[e.data.id]); postMessage({ message: 'timeout:cleared', id: e.data.id }) delete intervalIds[e.data.id]; break; }}
4、新建workerTimer.js
这个可以随便命名
// workerTimer.jsimport Worker from './web.worker'// 参数1是页面路径,参数2是配置参数let worker = new Worker();console.log(Worker)let 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; }, setTimeout: function (cb, timeout, context) { this.id++; var id = this.id; this.callbacks[id] = { fn: cb, context: context }; worker.postMessage({ command: 'timeout:start', timeout: timeout, id: id }); return id; }, // 监听worker 里面的定时器发送的message 然后执行回调函数 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 'timeout: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; case 'timeout:cleared': delete this.callbacks[e.data.id]; break; } }, // 往worker里面发送销毁指令 clearInterval: function (id) { worker.postMessage({ command: 'interval:clear', id: id }); }, clearTimeout: function (id) { worker.postMessage({ command: 'timeout:clear', id: id }); }};worker.onmessage = workerTimer.onMessage.bind(workerTimer);export default workerTimer
5、使用方法
<template> <div id="app"></div> </template> <script> import workerTimer from "./utils/workerTimer"; console.log(workerTimer); export default { name: "App", components: {}, data() { return {}; }, created() { this.init(); }, methods: { init() { let index = 0; let time = Date.parse(new Date()); const that = this; let intervalId intervalId = workerTimer.setInterval(function () { let newtime = Date.parse(new Date()); index++; console.log("当前执行次数" + index); console.log("当前时间秒:" + (newtime - time) / 1000); if(index>10){ workerTimer.clearInterval(intervalId) } }, 1000); }, }, }; </script>