找回密码
 会员注册
查看: 14|回复: 0

WebWorker

[复制链接]

3

主题

0

回帖

10

积分

新手上路

积分
10
发表于 2024-10-9 19:34:51 | 显示全部楼层 |阅读模式
这是第 141篇不掺水的,想要了解更多,请戳下方卡片关注我们吧~WebWorkerhttps://www.zoo.team/article/web-worker前言众所周知,JavaScript 是单线程的语言。当我们面临需要大量计算的场景时(比如视频解码等),UI 线程就会被阻塞,甚至浏览器直接卡死。现在前端遇到大量计算的场景越来越多,为了有更好的体验,HTML5 中提出了 Web Worker 的概念。Web Worker 可以使脚本运行在新的线程中,它们独立于主线程,可以进行大量的计算活动,而不会影响主线程的 UI 渲染。当计算结束之后,它们可以把结果发送给主线程,从而形成了高效、良好的用户体验。Web Worker 是一个统称,具体可以细分为普通的 Worker、SharedWorker 和 ServiceWorker 等,接下来我们一一介绍其使用方法和适合的场景。普通 Worker创建 Worker 通过 new 的方式来生成一个实例,参数为 url 地址,该地址必须和其创建者是同源的。constworker=newWorker('./worker.js');//参数是url,这个url必须与创建者同源Worker 的方法onmessage 主线程中可以在 Worker 上添加 onmessage 方法,用于监听 Worker 的信息。示例:constworker=newWorker('./worker.js');worker.onmessage=function(messageEvent){console.log(messageEvent)}onmessageerror 主线程中可以在 Worker 上添加 onmessageerror 方法,用于监听 Worker 的错误信息。示例:constworker=newWorker('./worker.js');worker.onmessageerror=function(messageEvent){console.log(messageEvent)}postMessage() 主线程通过此方法给 Worker 发送消息,发送参数的格式不限(可以是数组、对象、字符串等),可以根据自己的业务选择。示例:constworker=newWorker('./worker.js');worker.postMessage({type:'start',payload:{count:666}});//发送信息给workerterminate() 主线程通过此方法终止 Worker 的运行。示例:constworker=newWorker('./worker.js');worker.terminate();通信Worker 的作用域跟主线程中的 Window 是相互独立的,并且 Worker 中是获取不到 DOM 元素的。所以在 Worker 中你无法使用 Window 变量。取而代之的是可以用 self 来表示全局对象。self 上有哪些方法和属性,感兴趣的小伙伴可以自行输出查看。比较常用的方法是 onmessage、postMessage,主要用来跟主线程进行通信。示例://监听事件,主线程可以通过postMessage发送信息过来self.onmessage=(messageEvent)=>{const{type,payload}=messageEvent.data;switch(type){case'start'://通过type去区分不同的业务逻辑,payload是传过来的数据constresult=0;//....,通过一系列处理之后,把最终的结果发送给主线程this.postMessage(result);break;}};这里我们从 messageEvent.data 中获取从主线程传递过来的数据。为了业务的扩展性,这边是以 type 去区分不同的业务,payload 承载数据源,通过处理之后把结果发给主线程。主线程的 onmessage 回调函数中就能收到这个结果了。Worker 中引用其他脚本的方式跟常用的 JavaScript 一样,Worker 中也是可以引入其他的模块的。但是方式不太一样,是通过 importScripts 来引入。这边我为了演示,新建了一个 constant.js。在 constant.js 定义了一些变量和函数。示例://Worker.jsimportScripts('constant.js');//下面就可以获取到constant.js中的所有变量了//constant.js//可以在Worker中使用consta=111;//不可以在 Worker 中使用,原因未知constb=function(){console.log('test');};//可以在Worker中使用functionc(){console.log('test');}调试方法写代码难免要进行调试。Worker 的调试在浏览器控制台中有专门展示的地方,见下图。常见使用场景一般的视频网站 以优酷为例,当我们开始播放优酷视频的时候,就能看到它会调用 Worker,解码的代码应该写在 Worker 里面。需要大量计算的网站 比如 imgcook 这个网站,它能在前端解析 sketch 文件,这部分解析的逻辑就写在 Worker 里。SharedWorkerSharedWorker 是一种特定的 Worker。从它的命名就能知道,它是一种共享数据的 Worker。它可以同时被多个浏览器环境访问。这些浏览器环境可以是多个 window, iframes 或者甚至是多个 Worker,只要这些 Workers 处于同一主域。为跨浏览器 tab 共享数据提供了一种解决方案。创建 SharedWorker创建的方法跟上面普通 Worker 完全一模一样。constworker=newSharedWorker("./shareWorker.js");//参数是url,这个url必须与创建者同源SharedWorker 的方法SharedWorker 的方法都在 port 上,这是它与普通 Worker 不同的地方。port.onmessage主线程中可以在 worker 上添加 onmessage 方法,用于监听 SharedWorker 的信息示例:constsharedWorker=newSharedWorker('./shareWorker.js');sharedWorker.port.onmessage=function(messageEvent){console.log(messageEvent)}port.postMessage()主线程通过此方法给 SharedWorker 发送消息,发送参数的格式不限示例:constsharedWorker=newSharedWorker('./shareWorker.js');sharedWorker.port.postMessage({type:'increase',payload:{count:666}});port.start()主线程通过此方法开启 SharedWorker 之间的通信示例:constsharedWorker=newSharedWorker('./shareWorker.js');sharedWorker.port.start()port.close()主线程通过此方法关闭 SharedWorker示例:constsharedWorker=newSharedWorker('./shareWorker.js');sharedWorker.port.close()通信SharedWorker 跟普通的 Worker 一样,可以用 self 来表示全局对象。不同之处是,它需要等 port 连接成功之后,利用 port 的onmessage、postMessage,来跟主线程进行通信。当你打开多个窗口的时候,SharedWorker 的作用域是公用的,这也是其特点。示例://index.jsconstworker=newSharedWorker('./shareWorker.js');worker.port.start();//开启端口//发送信息给shareWorkerworker.port.postMessage({type:'increase',payload:{count:666}});//接受shareWorker发过来的数据worker.port.onmessage=function(val){console.log(val.data)};//shareWorker.jsletcount=666;port.onmessage=(messageEvent)=>{const{type,payload}=messageEvent.data;switch(type){case'increase':port.postMessage(++count);break;case'decrease':port.postMessage(--count);break;}};Worker 中引用其他脚本这个与普通的 Worker 方法一样,使用 importScripts调试方法在浏览器中查看和调试 SharedWorker 的代码,需要输入 chrome://inspect/ServiceWorkerServiceWorker 一般作为 Web 应用程序、浏览器和网络之间的代理服务。他们旨在创建有效的离线体验,拦截网络请求,以及根据网络是否可用采取合适的行动,更新驻留在服务器上的资源。他们还将允许访问推送通知和后台同步 API。创建 ServiceWorker//index.jsif('serviceWorker'innavigator){window.addEventListener('load',function(){navigator.serviceWorker.register('./serviceWorker.js',{scope:'/page/'}).then(function(registration){console.log('ServiceWorkerregistrationsuccessfulwithscope:',registration.scope);},function(err){console.log('ServiceWorkerregistrationfailed:',err);});});}只要创建了 ServiceWorker,不管这个创建 ServiceWorker 的 html 是否打开,这个 ServiceWorker 是一直存在的。它会代理范围是根据 scope 决定的,如果没有这个参数,则其代理范围是创建目录同级别以及子目录下所有页面的网络请求。代理的范围可以通过 registration.scope 查看。安装 ServiceWorker//serviceWorker.jsconstCACHE_NAME='cache-v1';//需要缓存的文件consturlsToCache=['/style/main.css','/constant.js','/serviceWorker.html','/page/index.html','/serviceWorker.js','/image/131.png',];self.oninstall=(event)=>{event.waitUntil(caches.open(CACHE_NAME)//这返回的是promise.then(function(cache){returncache.addAll(urlsToCache);//这返回的是promise}));};在上述代码中,我们可以看到,在 install 事件的回调中,我们打开了名字为 cache-v1 的缓存,它返回的是一个 promise。在打开缓存之后,我们需要把要缓存的文件 add 进去,基本上所有类型的资源都可以进行缓存,例子中缓存了 css、js、html、png。如果所有缓存数据都成功,就表示 ServiceWorker 安装成功;如果控制台提示 Uncaught (in promise) TypeError: Failed to execute 'Cache' on 'addAll': Request failed,则表示安装失败。缓存和返回请求self.onfetch=(event)=>{event.respondWith(caches.match(event.request)//此方法从服务工作线程所创建的任何缓存中查找缓存的结果.then(function(response){//response为匹配到的缓存资源,如果没有匹配到则返回undefined,需要fetch资源if(response){returnresponse;}returnfetch(event.request);}));};在 fetch 事件的回调中,我们去匹配 cache 中的资源。如果匹配到,则使用缓存资源;没有匹配到则用 fetch 请求。正因为 ServiceWorker 可以代理网络请求,所以为了安全起见,规范中规定它只能在 https 和 localhost 下才能开启。调试方法在浏览器中查看和调试 ServiceWorker 的代码,需要输入 chrome://inspect/#service-workers演示效果上面代码中,我缓存了 131.png。切换到离线模式,131 图片还是能显示,134.png 就获取不到了。看到这里,大家可能会有疑惑了。这个图片它存到哪里去了?实际上它会把文件自动存到浏览器的 Cache Storage 中。我们打开浏览器可以看到。常见使用场景缓存资源文件,加快渲染速度这个我们以语雀为例。我们在打开语雀网站的时候,可以看到它使用 ServiceWorker 缓存了很多 css、js 文件,从而达到优化的效果。总结类型WorkerSharedWorkerServiceWorker通信方式postMessageport.postMessage单向通信,通过addEventListener 监听serviceWorker 的状态使用场景适合大量计算的场景适合跨 tab、iframes之间共享数据缓存资源、网络优化兼容性>= IE 10>= Chrome 4不支持 IE、Safari、Android、iOS>= Chrome 4不支持 IE>= Chrome 40本文介绍了 3 种 Worker,他们分别适合不同的场景,总结如上面表格。普通的 Worker 可以在需要大量计算的时候使用,创建新的线程可以降低主线程的计算压力,不会导致 UI 卡顿。SharedWorker 主要是为不同的 window、iframes 之间共享数据提供了另外一个解决方案。ServiceWorker 可以缓存资源,提供离线服务或者是网络优化,加快 Web 应用的开启速度,更多是优化体验方面的。示例代码:https://github.com/Pulset/Web-Worker参考文献在网络应用中添加服务工作线程和离线功能(https://developers.google.com/web/fundamentals/codelabs/offline)Service worker overview(https://developer.chrome.com/docs/workbox/service-worker-overview/)Workers(https://developer.mozilla.org/zh-CN/docs/Web/API/Worker)SharedWorker(https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker)看完两件事如果你觉得这篇内容对你挺有启发,我想邀请你帮我两件小事1.点个「在看」,让更多人也能看到这篇内容(点了「在看」,bug -1 )2.关注公众号「政采云前端团队」,持续为你推送精选好文招贤纳士政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 60 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。如果你想改变一直被事折腾,希望开始能折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变既定的节奏,将会是“5 年工作时间 3 年工作经验”;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 ZooTeam@cai-inc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-29 13:00 , Processed in 0.514795 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表