webworker/浏览器空闲状态/不引入单独js

发布时间 2023-07-10 16:30:54作者: TheFirstDream

  想必大家都遇到过浏览器页面最小化、非当前聚焦页面(锁屏暂时没有尝试,按理是一样的)这些场景时,再次打开目标页面时,页面自动刷新了一下,或者重新加载了一次,明显可以看到卡顿了一下等等现象(不同浏览器策略有所不同)。体会最明显的就是比如我们写了一个时钟的页面,最小化等操作之前时间和机器时间是同步的,但是过了一会儿切回来的时候,时间就比机器时间慢了。

  有很多大佬也都分析对比过具体的变化规律,比如速度变慢多少,离开多长时间开始,timeout、interval等等不同的命令的表现差异,这里不再赘述。原因自然是系统电源选项为了节省耗电以及节省内存空间将页面假死闲置的一种策略。那么解决方法目前可行的就是webworker了。

  我们都知道webworker特性是为了实现多线程的概念而产生的,但是实际应用很有限。而应用的方法也很简单,引入一个js文件即可,消息传递和停止worker也都很简单,示例:

 1 // main.js(主线程)
 2 
 3 const myWorker = new Worker('/worker.js'); // 创建worker
 4 
 5 myWorker.addEventListener('message', e => { // 接收消息
 6     console.log(e.data); // Greeting from Worker.js,worker线程发送的消息
 7 });
 8 
 9 
10 myWorker.postMessage('Greeting from Main.js'); // 向 worker 线程发送消息,对应 worker 线程中的 e.data
11 
12 // worker.js(worker线程)
13 self.addEventListener('message', e => { // 接收到消息
14     console.log(e.data); // Greeting from Main.js,主线程发送的消息
15     self.postMessage('Greeting from Worker.js'); // 向主线程发送消息
16 });
17 
18 
19 // 参考链接:https://juejin.cn/post/7139718200177983524

具体用法不再赘述。这里需要强调的是,正常的使用时都需要一个单独的js文件,而如果我们想在控制台执行或者不想单独增加文件,就可以使用下边的方法:

 1 // 文件名为main.js
 2 function work () {
 3   onmessage = ({data: {message}}) => {
 4     console.log ('i am worker, receive:' + message);
 5     postMessage ({result: 'message from worker'});
 6   };
 7 }
 8 
 9 const runWorker = f => {
10   const worker = new Worker (
11     URL.createObjectURL (new Blob ([`(${f.toString ()})()`]))
12   );
13 
14   worker.onmessage = ({data: {result}}) => {
15     console.log ('i am main thread, receive:' + result);
16   };
17 
18   worker.postMessage ({message: 'message from main thread'});
19 };
20 
21 const testWorker = runWorker (work);
22 
23  
24 
25  
26 // 用Promise和闭包的方式去改造
27 // 我们再让它更通用一些,用Promise和闭包的方式去改造它,把runworker函数改造成一个makeworker函数
28 // 文件名为main.js
29 function work () {
30   onmessage = ({data: {jobId, message}}) => {
31     console.log ('i am worker, receive:-----' + message);
32     postMessage ({jobId, result: 'message from worker'});
33   };
34 }
35 
36 const makeWorker = f => {
37   let pendingJobs = {};
38 
39   const worker = new Worker (
40     URL.createObjectURL (new Blob ([`(${f.toString ()})()`]))
41   );
42 
43   worker.onmessage = ({data: {result, jobId}}) => {
44     // 调用resolve,改变Promise状态
45     pendingJobs[jobId] (result);
46     // 删掉,防止key冲突
47     delete pendingJobs[jobId];
48   };
49 
50   return (...message) =>
51     new Promise (resolve => {
52       const jobId = String (Math.random ());
53       pendingJobs[jobId] = resolve;
54       worker.postMessage ({jobId, message});
55     });
56 };
57 
58 const testWorker = makeWorker (work);
59 
60 testWorker ('message from main thread').then (message => {
61   console.log ('i am main thread, i receive:-----' + message);
62 });
63 // 参考链接https://www.lmlphp.com/user/16516/article/item/585417/