JavaScript如何解決單執行緒缺陷——webWorker

2023-06-08 18:00:12

解決JavaScript單執行緒問題——webWorkers

參考檔案 使用 Web Workers - Web API 介面參考 | MDN (mozilla.org)

MDN的介紹為:

Web Worker 為 Web 內容在後臺執行緒中執行指令碼提供了一種簡單的方法。執行緒可以執行任務而不干擾使用者介面。此外,它們可以使用 XMLHttpRequest(儘管 responseXMLchannel 屬性總是為空)或 fetch(沒有這些限制)執行 I/O。一旦建立,一個 worker 可以將訊息傳送到建立它的 JavaScript 程式碼,通過將訊息釋出到該程式碼指定的事件處理器(反之亦然)。

簡單來說就是, 我們可以通過使用worker為主執行緒分擔資料處理壓力.
假如說你有一段很大的資料需要處理, 而你又不想這段程式阻礙你的其他操作,這時候就可以考慮一下webWorker.

如何使用webWorker

建立worker

  1. 先建立一個worker.js檔案, 該檔案為執行緒程式碼檔案, 檔案中的程式碼會在後臺執行緒中執行.

  2. 在主執行緒中建立一個worker, 通過類似通訊的方式在主執行緒和worker中進行資料傳遞.

    // index.js主執行緒程式碼塊
    // 簡單建立一個worker名為myworker
    let myworker = new Worker("./firstworker.js") // 引數為firstworker.js檔案的路徑
    

主執行緒和worker之間進行通訊

  1. 主執行緒傳送資料給worker: 在主執行緒中通過 worker.prototype.postMessage() 進行通訊

    // index.js主執行緒程式碼塊
    // ... 建立完worker
    
    console.log("主執行緒我說句話先,接下來你要替我幹活了.");
    // 簡單向worker中傳送一個陣列[1, 2, 3]
    myworker.postMessage([1, 2, 3]);
    
  2. worker接收來自主執行緒的資料: 在myworker.js中接收資料

    // firstworker.js程式碼塊
    // 接收來自主執行緒的資料,陣列[1, 2, 3]
    onmessage = function recive(msg) {
        // 接收到的是一個MessageEvent物件, 我們可以獲取data屬性
        console.log(msg.data); // 輸出[1, 2, 3]
    };
    

    我們也可以使用更簡潔的方式

    // firstworker.js程式碼塊
    // 使用解構和匿名箭頭函數
    onmessage = ({ data }) => {
      console.log(data); // 輸出[1, 2, 3]
    };
    
  3. worker傳送資料給主執行緒: 通過 postMessage() 傳送資料給主執行緒 index.js

    接收到陣列[1, 2, 3]之後, 我們可以簡單的對陣列進行一個逆序操作, 再把結果返回主執行緒

    // firstworker.js程式碼塊
    onmessage = ({ data }) => {
        // 主執行緒發來的資料
        console.log("主執行緒發來的資料:", data);
        // 賦值一個新變數newdata
        let newdata = data;
        // 對新變數操作(陣列逆序)
        newdata.sort((a, b) => {
            return b - a;
        });
        console.log("worker後臺執行緒處理完成的資料newdata:", newdata);
        // 處理完的結果遞交給主執行緒
        postMessage(newdata);
    };
    
  4. 主執行緒接收worker訊息: 通過 addEventListener() 對worker的動作進行監聽

    // index.js主執行緒程式碼塊
    // 主執行緒通過 監聽 範例的message事件獲取worker的資料
    // 接收myworker處理之後的結果
    myworker.addEventListener("message", ({ data }) => {
        console.log("接收到來自worker處理完的資料:", data);
    });
    

關閉執行緒

worker.terminate()可以幫助我們在主執行緒中隨意關閉執行緒, 即為從主執行緒中立刻終止一個執行中的 worker

// index.js主執行緒程式碼塊
// 3s後關閉執行緒
setTimeout(() => {
    console.log("關閉myworker,你別說話了")
    myWorker.terminate();
}, 3000);

// firstworker.js程式碼塊
setTimeout(() => {
    console.log("4秒時讓我說句話")
}, 4000);

worker監聽

主執行緒通過 addEventListener() 對worker動作進行監聽, 動作包含三種

  • message
  • error
  • messageError:

注意事項

  1. worker是HTML5規範的API,所以你沒法在node環境中使用.
  2. worker沒辦法對dom元素操作, 只能在主執行緒中, 多執行緒操作dom感覺就不大好.
  3. worker可以用於執行長時間執行的計算、處理大量資料、執行網路請求等任務,而不會影響使用者介面的響應效能.幫助開發人員提高Web應用程式的效能和響應效能.
  4. 本文章只對worker的使用進行了簡單介紹, 具體進階用法等詳細內容還得參考MDN檔案(共用worker, 執行緒安全, 嵌入式worker等)