Web Worker 的正確打開方式

定義

Web Worker 在 MDN 上的解釋爲通過使用 Web Workers,Web 應用程序可以在獨立於主線程的後臺線程中,運行一個腳本操作。這樣做的好處是可以在獨立線程中執行費時的處理任務,從而允許主線程(通常是 UI 線程)不會因此被阻塞 / 放慢。

使用場景

Web Worker 的作用,就是爲 JavaScript 創造多線程環境,允許主線程創建 Worker 線程,將一些任務分配給後者運行。在主線程運行的同時,Worker 線程在後臺運行,兩者互不干擾。等到 Worker 線程完成計算任務,再把結果返回給主線程。這樣的好處是,一些計算密集型或高延遲的任務,被 Worker 線程負擔了,主線程(通常負責 UI 交互)就會很流暢。基於這一特性或者說優點,Web Worker 衍生出了以下幾種使用場景:

  1. 加密:端到端的加密由於對保護個人和敏感數據日益嚴格的法律規定而變得越來越流行。加密有時候會非常地耗時,特別是如果當你需要經常加密很多數據的時候(比如,發往服務器前加密數據)。這是一個使用 Web Worker 的絕佳場景,因爲它並不需要訪問 DOM 或者利用其它魔法-它只是純粹使用算法進行計算而已。一旦在 worker 進行計算,它對於用戶來說是無縫地且不會影響到用戶體驗。

  2. 預取數據:爲了優化網站或者網絡應用及提升數據加載時間,你可以使用 Workers 來提前加載部分數據以備不時之需。不像其它技術,Web Workers 在這種情況下是最棒噠,因爲它不會影響程序的使用體驗。

  3. 拼寫檢查:一個基本的拼寫檢測器是這樣工作的-程序會讀取一個包含拼寫正確的單詞列表的字典文件。字典會被解析成一個搜索樹以加快實際的文本搜索。當檢查器檢查一個單詞的時候,程序會在預構建搜索樹中進行檢索。如果在樹中沒有檢索到,則會通過提供替代的字符爲用戶提供替代的拼寫並檢測單詞是否是有效-是否是用戶需要的單詞。這個檢索過程中的所有工作都可以交由 Web Worker 來完成,這樣用戶就只需輸入單詞和語句而不會阻塞 UI,與此同時 worker 會處理所有的搜索和服務建議。

分類

Dedicated Workers(專用線程):由主進程實例化並且只能與之進行通信。

Shared workers(共享線程):可以被運行在同源的所有進程訪問(不同的瀏覽的選項卡,內聯框架及其它 shared workers)。

Service Workers(服務線程):由事件驅動的 worker,它由源和路徑組成。它可以控制它關聯的網頁,解釋且修改導航,資源的請求,以及一種非常細粒度的方式來緩存資源以讓你非常靈活地控制程序在某些情況下的行爲(比如網絡不可用)。

使用方法

const worker = new Worker('worker.js')
worker.postMessage('post message');
worker.onmessage = function (event) {
  doSomething();
}

function doSomething() {
  // 執行任務
  worker.postMessage('Work done!');
}
worker.terminate()
worker.onerror = function(e){ 
//打印出錯消息 
console.log(e.message);
//中斷與子線程的聯繫 
worker.terminate();
}

如今前端多爲 SPA 項目,如使用 Web Worker,還需要做一些處理。以下爲在 ES6+Webpack 的代碼工程環境下的使用方法。

$ npm install -D worker-loader # 或 $ yarn add worker-loader --dev
// main.js
const MyWorker = require("worker-loader!./file.js");
const worker = new MyWorker();
worker.postMessage({a: 1});
worker.onmessage = function(event) { /* 操作 */ };
worker.addEventListener("message"function(event) { /* 操作 */ });

優點:寫 worker 邏輯的腳本文件可以任意命名,只要傳進 worker-loader 中處理即可;缺點:每引入一次 worker 邏輯的腳本文件,就需要寫一次如上所示的代碼,需要多寫 N(N>=1) 次的 "worker-loader!"

rules: [
  {
    // 匹配 *.worker.js
    test: /\.worker\.js$/,
    use: {
      loader: 'worker-loader',
      options: {
        name: '[name]:[hash:8].js',
      }
    }
  }
]

侷限性

  1. 同源限制:分配給 Worker 線程運行的腳本文件,必須與主線程的腳本文件同源。

2.DOM 限制:Worker 線程所在的全局對象,與主線程不一樣,無法讀取主線程所在網頁的 DOM 對象,也無法使用documentwindowparent這些對象。但是,Worker 線程可以navigator對象和location對象。

  1. 通信聯繫:Worker 線程和主線程不在同一個上下文環境,它們不能直接通信,必須通過消息完成。

  2. 腳本限制:Worker 線程不能執行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 對象發出 AJAX 請求。

  3. 文件限制:Worker 線程無法讀取本地文件,即不能打開本機的文件系統(file://),它所加載的腳本,必須來自網絡。

兼容性

如下如,專用線程 Worker 的兼容性是較好的,但 SharedWorker 與 ServiceWorker 的兼容性不太理想。

總結

雖然可以通過使用 Web Worker 將代碼挪到另一個不同的線程執行從而任由 js 代碼阻塞,但是我們在實際工作中由於上文提到的侷限性以及兼容性導致用到 Web Worker 的場景是屈指可數的。不過通過衆多 fe 的努力以及不斷髮展的大前端,我相信 Web Worker 肯定會有發光發熱的一天。

參考文章

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/9ISGaRofG6hhh0g6DpGyTQ