你不知道的 Web Workers (上)

語言: CN / TW / HK

閲讀完本文你將學到以下知識:

  • 進程與線程的區別:進程與線程的概念及單線程與多線程;

  • 瀏覽器內核的相關知識:GUI 渲染線程、JavaScript 引擎線程、事件觸發線程等;

  • Web Workers 是什麼:Web Workers 的限制與能力及主線程與 Web Workers 之間如何通信;

  • Web Workers 的分類:Dedicated Worker、Shared Worker 和 Service Workers;

  • Web Workers API:Worker 構造函數及如何觀察 Dedicated Worker 等。

下面我們開始步入正題,為了讓大家能夠更好地理解和掌握 Web Workers,在正式介紹 Web Workers 之前,我們先來介紹一些與 Web Workers 相關的基礎知識。

一、進程與線程的區別

在介紹進程與線程的概念前,我們先來看個進程與線程之間關係形象的比喻:

如上圖所示,進程是一個工廠,它有獨立的資源,線程是工廠中的工人,多個工人協作完成任務,工人之間共享工廠內的資源,比如工廠內的食堂或餐廳。此外,工廠(進程)與工廠(進程)之間是相互獨立的。為了讓大家能夠更直觀地理解進程與線程的區別,我們繼續來看張圖:

由上圖可知,操作系統會為每個進程分配獨立的內存空間,一個進程由一個或多個線程組成,同個進程下的各個線程之間共享程序的內存空間。相信通過前面兩張圖,小夥伴們對進程和線程之間的區別已經有了一定的瞭解,那麼實際情況是不是這樣呢?這裏我們打開 macOS 操作系統下的活動監視器,來看一下寫作本文時所有進程的狀態:

通過上圖可知,我們常用的軟件,比如微信和搜狗輸入法都是一個獨立的進程,擁有不同的 PID(進程 ID),而且圖中的每個進程都含有多個線程,以微信進程為例,它就含有 「36」 個線程。那麼什麼是進程和線程呢?下面我們來介紹進程和線程的概念。

1.1 進程的概念

進程(英語:process),是指計算機中已運行的程序。進程曾經是分時系統的基本運作單位。在面向進程設計的系統(如早期的 UNIX,Linux 2.4 及更早的版本)中,進程是程序的基本執行實體; 「在面向線程設計的系統(如當代多數操作系統、Linux 2.6 及更新的版本)中,進程本身不是基本運行單位,而是線程的容器。」

程序本身只是指令、數據及其組織形式的描述,進程才是程序的真正運行實例。若干進程有可能與同一個程序相關係,且每個進程皆可以同步或異步的方式獨立運行。現代計算機系統可在同一段時間內以進程的形式將多個程序加載到存儲器中,並藉由時間共享(或稱時分複用),以在一個處理器上表現出同時運行的感覺。

1.2 線程的概念

線程(英語:thread)是操作系統能夠進行運算調度的最小單位。大部分情況下,它被包含在進程之中,是進程中的實際運作單位。 「一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務。」

線程是獨立調度和分派的基本單位。線程可以為操作系統內核調度的內核線程,如 Win32 線程;由用户進程自行調度的用户線程,如 Linux 平台的 POSIX Thread;或者由內核與用户進程,如 Windows 7 的線程,進行混合調度。

「同一進程中的多條線程將共享該進程中的全部系統資源,如虛擬地址空間,文件描述符和信號處理等等。」但同一進程中的多個線程有各自的調用棧(call stack),自己的寄存器環境(register context),自己的線程本地存儲(thread-local storage)。一個進程可以有很多線程,每條線程並行執行不同的任務。

1.3 單線程與多線程

如果一個進程只有一個線程,我們稱之為單線程。單線程在程序執行時,所走的程序路徑按照連續順序排下來,前面的必須處理好,後面的才會執行。單線程處理的優點:同步應用程序的開發比較容易,但由於需要在上一個任務完成後才能開始新的任務,所以其效率通常比多線程應用程序低。

如果完成同步任務所用的時間比預計時間長,應用程序可能會不響應。針對這個問題,我們可以考慮使用多線程,即在進程中使用多個線程,這樣就可以處理多個任務。

對於 Web 開發者熟悉的 JavaScript 來説,它運行在瀏覽器中,是單線程的,每個窗口一個 JavaScript 線程,既然是單線程的,在某個特定的時刻,只有特定的代碼能夠被執行,其它的代碼會被阻塞。

JS 中其實是沒有線程概念的,所謂的單線程也只是相對於多線程而言。JS 的設計初衷就沒有考慮這些,針對 JS 這種不具備並行任務處理的特性,我們稱之為 “單線程”。 —— 來自知乎 “如何證明 JavaScript 是單線程的?” @雲澹的回答

其實在瀏覽器內核(渲染進程)中除了 JavaScript 引擎線程之外,還含有 GUI 渲染線程、事件觸發線程、定時觸發器線程等。因此對於瀏覽器的渲染進程來説,它是多線程的。接下來我們來簡單介紹瀏覽器內核。

二、瀏覽器內核

「瀏覽器最核心的部分是 “Rendering Engine”,即 “渲染引擎”,不過我們一般習慣將之稱為 “瀏覽器內核”。」它主要包括以下線程:

下面我們來分別介紹渲染進程中的每個線程。

2.1 GUI 渲染線程

GUI 渲染線程負責渲染瀏覽器界面,解析 HTML,CSS,構建 DOM 樹和 RenderObject 樹,佈局和繪製等。當界面需要重繪(Repaint)或由於某種操作引發迴流(Reflow)時,該線程就會執行。

2.2 JavaScript 引擎線程

JavaScript 引擎線程負責解析 JavaScript 腳本並運行相關代碼。 JavaScript 引擎一直等待着任務隊列中任務的到來,然後進行處理,一個Tab頁(Renderer 進程)中無論什麼時候都只有一個 JavaScript 線程在運行 JavaScript 程序。

需要注意的是,GUI 渲染線程與 JavaScript 引擎線程是互斥的,所以如果 JavaScript 執行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染被阻塞。

2.3 事件觸發線程

當一個事件被觸發時該線程會把事件添加到待處理隊列的隊尾,等待 JavaScript 引擎的處理。這些事件可以是當前執行的代碼塊如定時任務、也可來自瀏覽器內核的其他線程如鼠標點擊、AJAX 異步請求等,但由於 JavaScript 引擎是單線程的,所有這些事件都得排隊等待 JavaScript 引擎處理。

2.4 定時觸發器線程

瀏覽器定時計數器並不是由 JavaScript 引擎計數的,這是因為 JavaScript 引擎是單線程的,如果處於阻塞線程狀態就會影響記計時的準確,所以通過單獨線程來計時並觸發定時是更為合理的方案。我們日常開發中常用的 setInterval 和 setTimeout 就在該線程中。

2.5 Http 異步請求線程

在 XMLHttpRequest 在連接後是通過瀏覽器新開一個線程請求, 將檢測到狀態變更時,如果設置有回調函數,異步線程就產生狀態變更事件放到 JavaScript 引擎的處理隊列中等待處理。

前面我們已經知道了,由於 JavaScript 引擎與 GUI 渲染線程是互斥的,如果 JavaScript 引擎執行了一些計算密集型或高延遲的任務,那麼會導致 GUI 渲染線程被阻塞或拖慢。那麼如何解決這個問題呢?嘿嘿,當然是使用本文的主角 —— Web Workers。

三、Web Workers 是什麼

Web Worker 是 HTML5 標準的一部分,這一規範定義了一套 API,它允許一段 JavaScript 程序運行在主線程之外的另外一個線程中。Web Worker 的作用,就是為 JavaScript 創造多線程環境,允許主線程創建 Worker 線程,將一些任務分配給後者運行。

在主線程運行的同時,Worker 線程在後台運行,兩者互不干擾。等到 Worker 線程完成計算任務,再把結果返回給主線程。這樣的好處是,可以在獨立線程中處理一些計算密集型或高延遲的任務,從而允許主線程(通常是 UI 線程)不會因此被阻塞或拖慢。

(圖片來源:https://thecodersblog.com/web-worker-and-implementation/)

3.1 Web Workers 的限制與能力

通常情況下,你可以在 Worker 線程中運行任意的代碼,但注意存在一些例外情況,比如: 「直接在 worker 線程中操縱 DOM 元素,或使用 window 對象中的某些方法和屬性。」 大部分 window 對象的方法和屬性是可以使用的,包括 WebSockets,以及諸如 IndexedDB 和 FireFox OS 中獨有的 Data Store API 這一類數據存儲機制。

下面我們以 Chrome 和 Opera 所使用的 Blink 渲染引擎為例,介紹該渲染引擎下 Web Worker 中所支持的常用 APIs:

  • Cache:Cache 接口為緩存的 Request / Response  對象對提供存儲機制,例如,作為ServiceWorker 生命週期的一部分。

  • CustomEvent:用於創建自定義事件。

  • Fetch:Fetch API 提供了一個獲取資源的接口(包括跨域請求)。任何使用過 XMLHttpRequest 的人都能輕鬆上手,而且新的 API 提供了更強大和靈活的功能集。

  • Promise:Promise 對象代表了未來將要發生的事件,用來傳遞異步操作的消息。

  • FileReader:FileReader 對象允許 Web 應用程序異步讀取存儲在用户計算機上的文件(或原始數據緩衝區)的內容,使用 File 或 Blob 對象指定要讀取的文件或數據。

  • IndexedDB:IndexedDB 是一種底層 API,用於客户端存儲大量結構化數據,包括文件/二進制大型對象(blobs)。

  • WebSocket:WebSocket 對象提供了用於創建和管理 WebSocket 連接,以及可以通過該連接發送和接收數據的 API。

  • XMLHttpRequest:XMLHttpRequest(XHR)對象用於與服務器交互。通過 XMLHttpRequest 可以在不刷新頁面的情況下請求特定 URL,獲取數據。這允許網頁在不影響用户操作的情況下,更新頁面的局部內容。

更多信息請參見: Functions and classes available to workers 。

3.2 主線程與 Web Workers 之間的通信

主線程和 Worker 線程相互之間使用 postMessage() 方法來發送信息,並且通過 onmessage 這個事件處理器來接收信息。數據的交互方式為傳遞副本,而不是直接共享數據。主線程與 Worker 線程的交互方式如下圖所示:

除此之外,Worker 還可以通過 XMLHttpRequest 來訪問網絡,只不過 XMLHttpRequest 對象的 responseXMLchannel 這兩個屬性的值將總是 null

四、Web Workers 的分類

Web Worker 規範中定義了兩類工作線程,分別是專用線程 Dedicated Worker 和共享線程 Shared Worker,其中,Dedicated Worker 只能為一個頁面所使用,而 Shared Worker 則可以被多個頁面所共享。

4.1 Dedicated Worker

一個專用 Worker 僅僅能被生成它的腳本所使用,其瀏覽器支持情況如下:

(圖片來源:[https://caniuse.com/#search=Web%20Workers](https://caniuse.com/#search=Web Workers))

需要注意的是,由於 Web Worker 有同源限制,所以在進行本地調試或運行以下示例的時候,需要先啟動本地服務器,直接使用 file:// 協議打開頁面的時候,會拋出以下異常:

Uncaught DOMException: Failed to construct 'Worker': 
Script at 'file:///**/*.js' cannot be accessed from origin 'null'.

4.1.1 專用線程 Dedicated Worker:Ping/Pong

「index.html」

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>專用線程 Dedicated Worker —— Ping/Pong</title>
  </head>
  <body>
    <h3>阿寶哥:專用線程 Dedicated Worker —— Ping/Pong</h3>
    <script>
      if (window.Worker) {
        let worker = new Worker("dw-ping-pong.js");
        worker.onmessage = (e) =>
          console.log(`Main: Received message - ${e.data}`);
        worker.postMessage("PING");
      } else {
        console.log("嗚嗚嗚,不支持 Web Worker");
      }
    </script>
  </body>
</html>

「dw-ping-pong.js」

onmessage = (e) => {
  console.log(`Worker: Received message - ${e.data}`);
  postMessage("PONG");
}

以上代碼成功運行後,瀏覽器控制枱會輸出以下結果:

Worker: Received message - PING
Main: Received message - PONG

每個 Web Worker 都可以創建自己的子 Worker,這允許我們將任務分散到多個線程。創建子 Worker 也很簡單,具體我們來看個例子。

4.1.2 專用線程 Dedicated Sub Worker:Ping/Pong

「index.html」

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>專用線程 Dedicated Sub Worker —— Ping/Pong</title>
  </head>
  <body>
    <h3>阿寶哥:專用線程 Dedicated Sub Worker —— Ping/Pong</h3>
    <script>
      if (window.Worker) {
        let worker = new Worker("dw-ping-pong.js");
        worker.onmessage = (e) =>
          console.log(`Main: Received message - ${e.data}`);
        worker.postMessage("PING");
      } else {
        console.log("嗚嗚嗚,不支持 Web Worker");
      }
    </script>
  </body>
</html>

「dw-ping-pong.js」

onmessage = (e) => {
  console.log(`Worker: Received message - ${e.data}`);
  setTimeout(() => {
    let worker = new Worker("dw-sub-ping-pong.js");
    worker.onmessage = (e) => console.log(`Worker: Received from sub worker - ${e.data}`);
    worker.postMessage("PING");
  }, 1000);
  postMessage("PONG");
};

「dw-sub-ping-pong.js」

onmessage = (e) => {
  console.log(`Sub Worker: Received message - ${e.data}`);
  postMessage("PONG");
};

以上代碼成功運行後,瀏覽器控制枱會輸出以下結果:

Worker: Received message - PING
Main: Received message - PONG
Sub Worker: Received message - PING
Received from sub worker - PONG

4.1.3 專用線程 Dedicated Worker:importScripts

其實在 Web Worker 中,我們也可以使用 importScripts 方法將一個或多個腳本同步導入到 Web Worker 的作用域中。同樣我們來舉個例子。

「index.html」

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>專用線程 Dedicated Worker —— importScripts</title>
  </head>
  <body>
    <h3>阿寶哥:專用線程 Dedicated Worker —— importScripts</h3>
    <script>
      let worker = new Worker("worker.js");
      worker.onmessage = (e) => console.log(`Main: Received kebab case message - ${e.data}`);
      worker.postMessage(
        "Hello, My name is semlinker."
      );
    </script>
  </body>
</html>

「worker.js」

importScripts("https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.15/lodash.min.js");

onmessage = ({ data }) => {
  postMessage(_.kebabCase(data));
};

以上代碼成功運行後,瀏覽器控制枱會輸出以下結果:

Main: Received kebab case message - hello-my-name-is-semlinker

4.1.4 專用線程 Dedicated Worker:inline-worker

在前面的例子中,我們都是使用外部的 Worker 腳本來創建 Web Worker 對象。其實你也可以通過 Blob URL 或 Data URL 的形式來創建 Web Worker,這類 Worker 也被稱為 Inline Worker。

「1. 使用 Blob URL 創建 Inline Worker」

Blob URL/Object URL 是一種偽協議,允許 Blob 和 File 對象用作圖像,下載二進制數據鏈接等的 URL 源。在瀏覽器中,我們使用 URL.createObjectURL 方法來創建 Blob URL,該方法接收一個 Blob 對象,併為其創建一個唯一的 URL,其形式為 blob:<origin>/<uuid> ,對應的示例如下:

blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f641

瀏覽器內部為每個通過 URL.createObjectURL 生成的 URL 存儲了一個 URL → Blob 映射。因此,此類 URL 較短,但可以訪問 Blob 。生成的 URL 僅在當前文檔打開的狀態下才有效。它允許引用 <img><a> 中的 Blob ,但如果你訪問的 Blob URL 不再存在,則會從瀏覽器中收到 404 錯誤。

const url = URL.createObjectURL(
  new Blob([`postMessage("Dedicated Worker created by Blob")`])
);

let worker = new Worker(url);
worker.onmessage = (e) =>
  console.log(`Main: Received message - ${e.data}`);

除了在代碼中使用字符串動態創建 Worker 腳本,也可以把 Worker 腳本使用類型為 javascript/workerscript 標籤內嵌在頁面中,具體如下所示:

<script id="myWorker" type="javascript/worker">
   self['onmessage'] = function(event) {
     postMessage('Hello, ' + event.data.name + '!');
   };
</script>

接着就是通過 script 對象的 textContent 屬性來獲取對應的內容,然後使用 Blob API 和 createObjectURL API 來最終創建 Web Worker:

<script>
  let workerScript = document.querySelector('#myWorker').textContent;
  let blob = new Blob(workerScript, {type: "text/javascript"});
  let worker = new Worker(URL.createObjectURL(blob));
</script>

「2. 使用 Data URL 創建 Inline Worker」

Data URLs 由四個部分組成:前綴( data: )、指示數據類型的 MIME 類型、如果非文本則為可選的 base64 標記、數據本身:

data:[<mediatype>][;base64],<data>

mediatype 是個 MIME 類型的字符串,例如 " image/jpeg " 表示 JPEG 圖像文件。如果被省略,則默認值為 text/plain;charset=US-ASCII 。如果數據是文本類型,你可以直接將文本嵌入(根據文檔類型,使用合適的實體字符或轉義字符)。如果是二進制數據,你可以將數據進行 base64 編碼之後再進行嵌入。

const url = `data:application/javascript,${encodeURIComponent(
  `postMessage("Dedicated Worker created by Data URL")`
)}`;

let worker = new Worker(url);
worker.onmessage = (e) =>
  console.log(`Main: Received message - ${e.data}`);

4.2 Shared Worker

一個共享 Worker 是一種特殊類型的 Worker,可以被多個瀏覽上下文訪問,比如多個 windows,iframes 和 workers,但這些瀏覽上下文必須同源。相比 dedicated workers,它們擁有不同的作用域。其瀏覽器支持情況如下:

(圖片來源:[https://caniuse.com/#search=Web%20Workers](https://caniuse.com/#search=Web Workers))

與常規的 Worker 不同,首先我們需要使用 onconnect 方法等待連接,然後我們獲得一個端口,該端口是我們與窗口之間的連接。

4.2.1 共享線程 Shared Worker:點贊計數器

「index.html」

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>共享線程 Shared Worker</title>
  </head>
  <body>
    <h3>阿寶哥:共享線程 Shared Worker</h3>
    <button id="likeBtn">點贊</button>
    <p>阿寶哥一共收穫了<span id="likedCount">0</span>個:+1:</p>
    <script>
      let likes = 0;
      let likeBtn = document.querySelector("#likeBtn");
      let likedCountEl = document.querySelector("#likedCount");

      let worker = new SharedWorker("shared-worker.js");
      worker.port.start();

      likeBtn.addEventListener("click", function () {
        worker.port.postMessage("like");
      });

      worker.port.onmessage = function (val) {
        likedCountEl.innerHTML = val.data;
      };
    </script>
  </body>
</html>

「shared-worker.js」

let a = 666;

console.log("shared-worker");
onconnect = function (e) {
  var port = e.ports[0];

  port.onmessage = function () {
    port.postMessage(a++);
  };
};

在 Shared Worker 的示例頁面上有一個 「點贊」 按鈕,每次點擊時點贊數會加 1。首先你新開一個窗口,然後點擊幾次。然後新開另一個窗口繼續點擊,這時你會發現當前頁面顯示的點贊數是基於前一個頁面的點贊數繼續累加。

4.2.2 調試 Shared Workers

在實際項目開發過程中,若需要調試 Shared Workers 中的腳本,可以通過 chrome://inspect 來進行調試,具體步驟如下圖所示:

4.3 Service Workers

Service workers 本質上充當 Web 應用程序與瀏覽器之間的代理服務器,也可以在網絡可用時作為瀏覽器和網絡間的代理。它們旨在(除其他之外)使得能夠創建有效的離線體驗,攔截網絡請求並基於網絡是否可用以及更新的資源是否駐留在服務器上來採取適當的動作。

(圖片來源:https://www.pavlompas.com/blog/web-workers-vs-service-workers-vs-worklets)

Service workers 的瀏覽器支持情況如下:

由於 Service workers 不是本文的重點,這裏阿寶哥就不展開介紹了,感興趣的小夥伴請自行了解一下。下面我們開始介紹 Web Workers API。

五、Web Workers API

Worker() 構造函數創建一個 Worker 對象,該對象執行指定的URL腳本。這個腳本必須遵守同源策略 。如果違反同源策略,則會拋出一個 SECURITY_ERR 類型的 DOMException。

5.1 Worker 構造函數

Worker 構造函數的語法為:

const myWorker = new Worker(aURL, options);

相關的參數説明如下:

  • aURL:是一個 DOMString 表示 worker 將執行的腳本的 URL。它必須遵守同源策略。

  • options(可選):包含可在創建對象實例時設置的選項屬性的對象。可用屬性如下:

    • type:用以指定 Worker 類型的  DOMString 值. 該值可以是 classic 或 module。如果未指定,將使用默認值 classic。

    • credentials:用以指定 worker 憑證的 DOMString 值。該值可以是 omit,same-origin 或 include。如果未指定,或者 type 是 classic,將使用默認值 omit (不要求憑證)。

    • name:在 DedicatedWorkerGlobalScope 的情況下,用來表示 Worker 的 scope 的一個 DOMString 值,主要用於調試目的。

需要注意的是,在創建 Web Worker 的時候,可能會出現以下異常:

  • 當 document 不被允許啟動 worker 的時候,將拋出一個 SecurityError 異常。比如:如果提供的 aURL 有語法錯誤,或者與同源策略相沖突(跨域訪問)。

  • 如果 worker 的 MIME 類型不正確,將拋出一個 NetworkError 異常。worker 的 MIME 類型必須是 text/javascript
  • 如果 aURL 無法被解析(格式錯誤),將拋出一個 SyntaxError 異常。

「示例」

const worker = new Worker("task.js");

當我們調用 Worker 構造函數後會返回一個 Worker 線程對象,用來供主線程操作 Worker。Worker 線程對象的屬性和方法如下:

  • Worker.onerror:指定 error 事件的監聽函數。

  • Worker.onmessage:指定 message 事件的監聽函數,發送過來的數據在 Event.data 屬性中。
  • Worker.onmessageerror:指定 messageerror 事件的監聽函數。發送的數據無法序列化成字符串時,會觸發這個事件。

  • Worker.postMessage():向 Worker 線程發送消息。

  • Worker.terminate():立即終止 Worker 線程。

5.2 Dedicated Worker 示例

下面我們再來舉一個 Dedicated Worker 的例子:

「index.html」

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Dedicated Worker Demo</title>
  </head>
  <body>
    <h3>Dedicated Worker Demo</h3>
    <script>
      const worker = new Worker("task.js");

      worker.postMessage({
        id: 666,
        msg: "Hello Semlinker",
      });

      worker.onmessage = function (message) {
        let data = message.data;
        console.log(`Main: Message from worker ${JSON.stringify(data)}`);
        worker.terminate();
      };

      worker.onerror = function (error) {
        console.log(error.filename, error.lineno, error.message);
      };
    </script>
  </body>
</html>

「task.js」

而 Dedicated Worker 所執行的代碼如下所示:

onmessage = function (message) {
  let data = message.data;
  console.log(`Worker: Message from main thread ${JSON.stringify(data)}`);
  data.msg = "Hi from task.js";
  postMessage(data);
};

以上代碼成功運行後,控制枱會輸出以下結果:

Worker: Message from main thread {"id": 666,"msg": "Hello Semlinker"}
worker-demo.html:20 Main: Message from worker {"id":666, "msg":"Hi from task.js"}

為了讓大家更好的理解 Web Worker 的工作流程,我們來了解一下 WebKit 加載並執行 Worker 線程的流程:

(圖片來源:http://www.alloyteam.com/2015/11/deep-in-web-worker/)

5.3 觀察 Dedicated Worker

看到這裏相信有些小夥伴會好奇,介紹了那麼多 Web Worker 的相關知識,在哪裏可以直觀地感受到 Web Worker,接下來我們將從以下兩個角度來觀察它。

5.3.1 開發者工具

這裏阿寶哥以 Chrome 瀏覽器為例,首先打開 Chrome 開發者工具,然後選擇 「Sources -> Page」

5.3.2 Chrome 任務管理器 & 活動監視器

打開 Chrome 任務管理器之後,我們可以找到當前 Tab 頁對應的進程 ID,即為 「5194」 ,接着我們打開 macOS 下的活動監視器,然後選中 「5194」 進程,然後對該進程進行取樣操作:

取樣完成後,可以看到當前渲染進程中完整的線程信息,紅框中標出的就是我們想要找的 「Dedicated Worker」

本來是想一口氣寫完 「“你不知道的 Web Workers”」 ,但考慮到部分小夥伴們的感受,避免出現以下羣友提到的情況,阿寶哥決定拆成上下兩篇。

下篇阿寶哥將着重介紹 「Web Worker 一些常見的使用場景和 Deno Web Workers 的相關實現」 ,感興趣的小夥們記得持續關注阿寶哥喲。

六、參考資源

  • w3.org - workers

  • MDN - Web_Workers_API

  • web-workers-vs-service-workers-vs-worklets

  • introduction-to-web-worker

  • web-workers-demystified

  • 深入理解 Web Worker

  • 從瀏覽器多進程到JS單線程,JS運行機制最全面的一次梳理

往期精彩回顧

你不知道的 Blob

你不知道的 WeakMap

聚焦全棧,專注分享 Angular、TypeScript、Node.js 技術棧等全棧乾貨。

回覆  0  進入 重學TypeScript 學習羣

回覆  1 獲取 全棧修仙之路 博客地址

分享到: