<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Web Worker

          共 7782字,需瀏覽 16分鐘

           ·

          2022-05-23 18:19

          Web?Worker

          https://www.zoo.team/article/web-worker

          598e267c883caee12d8ff02086a4ec61.webp

          前言

          眾所周知,JavaScript 是單線程的語言。當(dāng)我們面臨需要大量計(jì)算的場(chǎng)景時(shí)(比如視頻解碼等),UI 線程就會(huì)被阻塞,甚至瀏覽器直接卡死。現(xiàn)在前端遇到大量計(jì)算的場(chǎng)景越來越多,為了有更好的體驗(yàn),HTML5 中提出了 Web Worker 的概念。Web Worker 可以使腳本運(yùn)行在新的線程中,它們獨(dú)立于主線程,可以進(jìn)行大量的計(jì)算活動(dòng),而不會(huì)影響主線程的 UI 渲染。當(dāng)計(jì)算結(jié)束之后,它們可以把結(jié)果發(fā)送給主線程,從而形成了高效、良好的用戶體驗(yàn)。Web Worker 是一個(gè)統(tǒng)稱,具體可以細(xì)分為普通的 Worker、SharedWorker 和 ServiceWorker 等,接下來我們一一介紹其使用方法和適合的場(chǎng)景。

          普通 Worker

          1. 創(chuàng)建 Worker 通過 new 的方式來生成一個(gè)實(shí)例,參數(shù)為 url 地址,該地址必須和其創(chuàng)建者是同源的。
          const?worker?=?new?Worker('./worker.js');?//?參數(shù)是?url,這個(gè)?url?必須與創(chuàng)建者同源?
          1. Worker 的方法
          • onmessage 主線程中可以在 Worker 上添加 onmessage 方法,用于監(jiān)聽 Worker 的信息。

            示例:

          const?worker?=?new?Worker('./worker.js');
          worker.onmessage?=?function?(messageEvent)?{
          ?console.log(messageEvent)
          }?
          • onmessageerror 主線程中可以在 Worker 上添加 onmessageerror 方法,用于監(jiān)聽 Worker 的錯(cuò)誤信息。

            示例:

          const?worker?=?new?Worker('./worker.js');
          worker.onmessageerror?=?function?(messageEvent)?{
          ?console.log(messageEvent)
          }?
          • postMessage() 主線程通過此方法給 Worker 發(fā)送消息,發(fā)送參數(shù)的格式不限(可以是數(shù)組、對(duì)象、字符串等),可以根據(jù)自己的業(yè)務(wù)選擇。

            示例:

          const?worker?=?new?Worker('./worker.js');
          worker.postMessage({?type:?'start',?payload:?{?count:?666?}?});?//?發(fā)送信息給worker
          • terminate() 主線程通過此方法終止 Worker 的運(yùn)行。

            示例:

          const?worker?=?new?Worker('./worker.js');
          worker.terminate();
          1. 通信

            Worker 的作用域跟主線程中的 Window 是相互獨(dú)立的,并且 Worker 中是獲取不到 DOM 元素的。所以在 Worker 中你無法使用 Window 變量。取而代之的是可以用 self 來表示全局對(duì)象。self 上有哪些方法和屬性,感興趣的小伙伴可以自行輸出查看。比較常用的方法是 onmessage、postMessage,主要用來跟主線程進(jìn)行通信。

            示例:

          //?監(jiān)聽事件,主線程可以通過?postMessage?發(fā)送信息過來
          self.onmessage?=?(messageEvent)?=>?{
          ?const?{?type,?payload?}?=?messageEvent.data;
          ??switch?(type)?{
          ????case?'start':
          ??????//?通過?type?去區(qū)分不同的業(yè)務(wù)邏輯,payload?是傳過來的數(shù)據(jù)
          ??????const?result?=?0;
          ??????//?....,通過一系列處理之后,把最終的結(jié)果發(fā)送給主線程
          ??????this.postMessage(result);
          ??????break;
          ??}
          };

          這里我們從 messageEvent.data 中獲取從主線程傳遞過來的數(shù)據(jù)。為了業(yè)務(wù)的擴(kuò)展性,這邊是以 type 去區(qū)分不同的業(yè)務(wù),payload 承載數(shù)據(jù)源,通過處理之后把結(jié)果發(fā)給主線程。主線程的 onmessage 回調(diào)函數(shù)中就能收到這個(gè)結(jié)果了。

          1. Worker 中引用其他腳本的方式

          跟常用的 JavaScript 一樣,Worker 中也是可以引入其他的模塊的。但是方式不太一樣,是通過 importScripts 來引入。這邊我為了演示,新建了一個(gè) constant.js。在 constant.js 定義了一些變量和函數(shù)。

          示例:

          //?Worker.js
          importScripts('constant.js');
          //?下面就可以獲取到?constant.js?中的所有變量了

          //?constant.js
          //?可以在?Worker?中使用
          const?a?=?111;

          //?不可以在 Worker 中使用,原因未知
          const?b?=?function?()?{
          ??console.log('test');
          };

          //?可以在?Worker?中使用
          function?c()?{
          ??console.log('test');
          }
          1. 調(diào)試方法

            寫代碼難免要進(jìn)行調(diào)試。Worker 的調(diào)試在瀏覽器控制臺(tái)中有專門展示的地方,見下圖。

          9550eb597c6d4b9c7556cbfefa80795d.webp
          1. 常見使用場(chǎng)景

          • 一般的視頻網(wǎng)站 以優(yōu)酷為例,當(dāng)我們開始播放優(yōu)酷視頻的時(shí)候,就能看到它會(huì)調(diào)用 Worker,解碼的代碼應(yīng)該寫在 Worker 里面。

            816e97fabb1a68880d9ddb0512af7e60.webp
          • 需要大量計(jì)算的網(wǎng)站 比如 imgcook 這個(gè)網(wǎng)站,它能在前端解析 sketch 文件,這部分解析的邏輯就寫在 Worker 里。

            e1ca29cd4f0363577c32798a73c91af3.webp

          SharedWorker

          SharedWorker 是一種特定的 Worker。從它的命名就能知道,它是一種共享數(shù)據(jù)的 Worker。它可以同時(shí)被多個(gè)瀏覽器環(huán)境訪問。這些瀏覽器環(huán)境可以是多個(gè) window, iframes 或者甚至是多個(gè) Worker,只要這些 Workers 處于同一主域。為跨瀏覽器 tab 共享數(shù)據(jù)提供了一種解決方案。

          1. 創(chuàng)建 SharedWorker

            創(chuàng)建的方法跟上面普通 Worker 完全一模一樣。

          const?worker?=?new?SharedWorker("./shareWorker.js");?//?參數(shù)是?url,這個(gè)?url?必須與創(chuàng)建者同源?
          1. SharedWorker 的方法

            SharedWorker 的方法都在 port 上,這是它與普通 Worker 不同的地方。

          • port.onmessage

            主線程中可以在 worker 上添加 onmessage 方法,用于監(jiān)聽 SharedWorker 的信息

            示例:

          const?sharedWorker?=?new?SharedWorker('./shareWorker.js');
          sharedWorker.port.onmessage?=?function?(messageEvent)?{
          ??console.log(messageEvent)
          }?
          • port.postMessage()

            主線程通過此方法給 SharedWorker 發(fā)送消息,發(fā)送參數(shù)的格式不限

            示例:

          const?sharedWorker?=?new?SharedWorker('./shareWorker.js');
          sharedWorker.port.postMessage({?type:?'increase',?payload:?{?count:?666?}?});
          • port.start()

            主線程通過此方法開啟 SharedWorker 之間的通信

            示例:

          const?sharedWorker?=?new?SharedWorker('./shareWorker.js');
          sharedWorker.port.start()
          • port.close()

            主線程通過此方法關(guān)閉 SharedWorker

            示例:

          const?sharedWorker?=?new?SharedWorker('./shareWorker.js');
          sharedWorker.port.close()
          1. 通信

            SharedWorker 跟普通的 Worker 一樣,可以用 self 來表示全局對(duì)象。不同之處是,它需要等 port 連接成功之后,利用 port 的onmessage、postMessage,來跟主線程進(jìn)行通信。當(dāng)你打開多個(gè)窗口的時(shí)候,SharedWorker 的作用域是公用的,這也是其特點(diǎn)。

            示例:

          //?index.js
          const?worker?=?new?SharedWorker('./shareWorker.js');

          worker.port.start();?//?開啟端口

          //?發(fā)送信息給?shareWorker
          worker.port.postMessage({?type:?'increase',?payload:?{?count:?666?}?});?

          //?接受?shareWorker?發(fā)過來的數(shù)據(jù)
          worker.port.onmessage?=?function?(val)?{
          ??console.log(val.data)
          };

          //?shareWorker.js
          let?count?=?666;

          port.onmessage?=?(messageEvent)?=>?{
          ??const?{?type,?payload?}?=?messageEvent.data;

          ??switch?(type)?{
          ????case?'increase':
          ??????port.postMessage(++count);
          ??????break;
          ????case?'decrease':
          ??????port.postMessage(--count);
          ??????break;
          ??}
          };
          1. Worker 中引用其他腳本

            這個(gè)與普通的 Worker 方法一樣,使用 importScripts

          2. 調(diào)試方法

            在瀏覽器中查看和調(diào)試 SharedWorker 的代碼,需要輸入 chrome://inspect/

          9139e772b65e950a2f2e828585181382.webp

          ServiceWorker

          ServiceWorker 一般作為 Web 應(yīng)用程序、瀏覽器和網(wǎng)絡(luò)之間的代理服務(wù)。他們旨在創(chuàng)建有效的離線體驗(yàn),攔截網(wǎng)絡(luò)請(qǐng)求,以及根據(jù)網(wǎng)絡(luò)是否可用采取合適的行動(dòng),更新駐留在服務(wù)器上的資源。他們還將允許訪問推送通知和后臺(tái)同步 API。

          1. 創(chuàng)建 ServiceWorker
          //?index.js
          if?('serviceWorker'?in?navigator)?{
          ??window.addEventListener('load',?function?()?{
          ????navigator.serviceWorker
          ??????.register('./serviceWorker.js',?{?scope:?'/page/'?})
          ??????.then(
          ??????function?(registration)?{
          ????????console.log('ServiceWorker?registration?successful?with?scope:?',
          ????????????????????registration.scope);
          ??????},
          ??????function?(err)?{
          ????????console.log('ServiceWorker?registration?failed:?',?err);
          ??????}
          ????);
          ??});
          }

          只要?jiǎng)?chuàng)建了 ServiceWorker,不管這個(gè)創(chuàng)建 ServiceWorker 的 html 是否打開,這個(gè) ServiceWorker 是一直存在的。它會(huì)代理范圍是根據(jù) scope 決定的,如果沒有這個(gè)參數(shù),則其代理范圍是創(chuàng)建目錄同級(jí)別以及子目錄下所有頁面的網(wǎng)絡(luò)請(qǐng)求。代理的范圍可以通過 registration.scope 查看。

          1. 安裝 ServiceWorker
          //?serviceWorker.js
          const?CACHE_NAME?=?'cache-v1';
          //?需要緩存的文件
          const?urlsToCache?=?[
          ??'/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)?{
          ??????return?cache.addAll(urlsToCache);?//?這返回的是?promise
          ????})
          ??);
          };

          在上述代碼中,我們可以看到,在 install 事件的回調(diào)中,我們打開了名字為 cache-v1 的緩存,它返回的是一個(gè) promise。在打開緩存之后,我們需要把要緩存的文件 add 進(jìn)去,基本上所有類型的資源都可以進(jìn)行緩存,例子中緩存了 css、js、html、png。如果所有緩存數(shù)據(jù)都成功,就表示 ServiceWorker 安裝成功;如果控制臺(tái)提示 Uncaught (in promise) TypeError: Failed to execute 'Cache' on 'addAll': Request failed,則表示安裝失敗。

          1. 緩存和返回請(qǐng)求
          self.onfetch?=?(event)?=>?{
          ??event.respondWith(
          ????caches
          ????.match(event.request)?//?此方法從服務(wù)工作線程所創(chuàng)建的任何緩存中查找緩存的結(jié)果
          ????.then(function?(response)?{
          ??????//?response?為匹配到的緩存資源,如果沒有匹配到則返回?undefined,需要?fetch?資源
          ??????if?(response)?{
          ????????return?response;
          ??????}
          ??????return?fetch(event.request);
          ????})
          ??);
          };

          在 fetch 事件的回調(diào)中,我們?nèi)テヅ?cache 中的資源。如果匹配到,則使用緩存資源;沒有匹配到則用 fetch 請(qǐng)求。正因?yàn)?ServiceWorker 可以代理網(wǎng)絡(luò)請(qǐng)求,所以為了安全起見,規(guī)范中規(guī)定它只能在 https 和 localhost 下才能開啟。

          1. 調(diào)試方法

            在瀏覽器中查看和調(diào)試 ServiceWorker 的代碼,需要輸入 chrome://inspect/#service-workers

          5968dd39f390fbf16de6048bb8164022.webp
          1. 演示效果

          上面代碼中,我緩存了 131.png。切換到離線模式,131 圖片還是能顯示,134.png 就獲取不到了。

          d88f7e6419a8b071ff948766e40d70ba.webp

          看到這里,大家可能會(huì)有疑惑了。這個(gè)圖片它存到哪里去了?實(shí)際上它會(huì)把文件自動(dòng)存到瀏覽器的 Cache Storage 中。我們打開瀏覽器可以看到。

          4fd1c834d99ac2123e7b326fc6cb9ba9.webp
          1. 常見使用場(chǎng)景

            緩存資源文件,加快渲染速度

            這個(gè)我們以語雀為例。我們?cè)诖蜷_語雀網(wǎng)站的時(shí)候,可以看到它使用 ServiceWorker 緩存了很多 css、js 文件,從而達(dá)到優(yōu)化的效果。

          0769d16a1ba589a299fb711a52e985fc.webp

          總結(jié)

          類型WorkerSharedWorkerServiceWorker
          通信方式postMessageport.postMessage單向通信,通過
          addEventListener 監(jiān)聽
          serviceWorker 的狀態(tài)
          使用場(chǎng)景適合大量計(jì)算的場(chǎng)景適合跨 tab、iframes
          之間共享數(shù)據(jù)
          緩存資源、網(wǎng)絡(luò)優(yōu)化
          兼容性>= IE 10
          >= Chrome 4
          不支持 IE、Safari、Android、iOS
          >= Chrome 4
          不支持 IE
          >= Chrome 40

          本文介紹了 3 種 Worker,他們分別適合不同的場(chǎng)景,總結(jié)如上面表格。普通的 Worker 可以在需要大量計(jì)算的時(shí)候使用,創(chuàng)建新的線程可以降低主線程的計(jì)算壓力,不會(huì)導(dǎo)致 UI 卡頓。SharedWorker 主要是為不同的 window、iframes 之間共享數(shù)據(jù)提供了另外一個(gè)解決方案。ServiceWorker 可以緩存資源,提供離線服務(wù)或者是網(wǎng)絡(luò)優(yōu)化,加快 Web 應(yīng)用的開啟速度,更多是優(yōu)化體驗(yàn)方面的。

          示例代碼:https://github.com/Pulset/Web-Worker

          參考文獻(xiàn)

          • 在網(wǎng)絡(luò)應(yīng)用中添加服務(wù)工作線程和離線功能(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)

          看完兩件事

          如果你覺得這篇內(nèi)容對(duì)你挺有啟發(fā),我想邀請(qǐng)你幫我兩件小事

          1.點(diǎn)個(gè)「在看」,讓更多人也能看到這篇內(nèi)容(點(diǎn)了在看」,bug -1 ??

          2.關(guān)注公眾號(hào)「政采云前端團(tuán)隊(duì)」,持續(xù)為你推送精選好文

          招賢納士

          政采云前端團(tuán)隊(duì)(ZooTeam),一個(gè)年輕富有激情和創(chuàng)造力的前端團(tuán)隊(duì),隸屬于政采云產(chǎn)品研發(fā)部,Base 在風(fēng)景如畫的杭州。團(tuán)隊(duì)現(xiàn)有 60 余個(gè)前端小伙伴,平均年齡 27 歲,近 3 成是全棧工程師,妥妥的青年風(fēng)暴團(tuán)。成員構(gòu)成既有來自于阿里、網(wǎng)易的“老”兵,也有浙大、中科大、杭電等校的應(yīng)屆新人。團(tuán)隊(duì)在日常的業(yè)務(wù)對(duì)接之外,還在物料體系、工程平臺(tái)、搭建平臺(tái)、性能體驗(yàn)、云端應(yīng)用、數(shù)據(jù)分析及可視化等方向進(jìn)行技術(shù)探索和實(shí)戰(zhàn),推動(dòng)并落地了一系列的內(nèi)部技術(shù)產(chǎn)品,持續(xù)探索前端技術(shù)體系的新邊界。

          如果你想改變一直被事折騰,希望開始能折騰事;如果你想改變一直被告誡需要多些想法,卻無從破局;如果你想改變你有能力去做成那個(gè)結(jié)果,卻不需要你;如果你想改變你想做成的事需要一個(gè)團(tuán)隊(duì)去支撐,但沒你帶人的位置;如果你想改變既定的節(jié)奏,將會(huì)是“5 年工作時(shí)間 3 年工作經(jīng)驗(yàn)”;如果你想改變本來悟性不錯(cuò),但總是有那一層窗戶紙的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望參與到隨著業(yè)務(wù)騰飛的過程,親手推動(dòng)一個(gè)有著深入的業(yè)務(wù)理解、完善的技術(shù)體系、技術(shù)創(chuàng)造價(jià)值、影響力外溢的前端團(tuán)隊(duì)的成長(zhǎng)歷程,我覺得我們?cè)摿牧摹H魏螘r(shí)間,等著你寫點(diǎn)什么,發(fā)給 [email protected]


          瀏覽 55
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  乳交打奶炮泄精合集 | 一区二区三区四区五区在线 | 成人精品一区日本无码网站suv | 免费国产黄色片 | 欧美日日日日 |