1. 程式人生 > >js多執行緒Web Worker

js多執行緒Web Worker

我們知道JavaScript是單執行緒模型,即所有任務都在一個執行緒上完成,前面一個任務如果沒有執行完成,後面的任務就只能等待。如果在遇到耗時的計算時,程式就會阻塞在這裡,這對使用者來說時不可接受的。因此我們在遇到耗時或者大量計算的時候就可以使用web worker。

什麼是web worker?web worker可以為JavaScript建立多執行緒,且web worker 是執行在後臺的 JavaScript,獨立於其他指令碼,不會影響頁面的效能。主執行緒在執行的時候,worker也在後臺執行,兩者互不干擾,當worker執行緒完成任務後就可以將結果返回給主線。

使用Web Worker 有以下幾個使用注意點:

1. 同源限制
worker子執行緒必須與主執行緒是同源
2. DOM限制
Worker 執行緒所在的全域性物件,與主執行緒不一樣,無法讀取主執行緒所在網頁的 DOM 物件,也無法使用document、window、parent這些物件。但是,Worker 執行緒可以navigator物件和location物件。
3. 主執行緒與子執行緒間的通訊
Worker 執行緒和主執行緒不在同一個上下文環境,它們不能直接通訊,必須通過postMessage訊息完成。
4. 指令碼限制
Worker 執行緒不能執行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 物件發出 AJAX 請求。
5. 檔案限制


Worker 執行緒無法讀取本地檔案,即不能開啟本機的檔案系統(file://),它所載入的指令碼,必須來自網路。

基本使用–專用執行緒
專用執行緒會隨當前頁面的關閉而結束,所以專用執行緒只能被建立它的頁面訪問

  1. 主執行緒
// 判斷瀏覽器是否支援worker執行緒
if(window.Worker) {
    // 主執行緒通過new 來開啟子執行緒,Worker建構函式的引數是一個指令碼檔案,由於Worker不能讀取本地檔案,因此該檔案必須是來源於網路
    // 本地通過搭建臨時服務來讀取指令碼檔案,但是在線上環境需要填寫網路路徑,且必須是同源
    var worker = new Worker
('./worker.js'); worker.postMessage('hello worker!'); } else { console.log('瀏覽器不支援worker子執行緒。。。'); } worker.addEventListener('message', function(res) { console.log('收到子執行緒的訊息:' + JSON.stringify(res.data)); // 關閉worker執行緒 worker.terminate(); })
  1. 子執行緒
// 通過監聽message來接受主執行緒中的訊息
addEventListener('message', function(res) {
    // 子執行緒向主執行緒中發生訊息
    this.postMessage('已收到主執行緒的訊息。。。');
})

開啟臨時服務結果:
在這裡插入圖片描述

沒有開啟臨時服務時,會報錯
在這裡插入圖片描述

基本使用–共享執行緒
共享執行緒可以被多個頁面訪問,因此只有當所有關聯的的頁面都關閉的時候,共享執行緒才會結束,共享執行緒必須帶上port

1> 主執行緒頁面index.html
向共享子執行緒中傳送資料

// 判斷瀏覽器是否支援worker執行緒
if(window.SharedWorker) {
    // 主執行緒通過new 來開啟共享子執行緒,SharedWorker建構函式的引數是一個指令碼檔案,由於SharedWorker不能讀取本地檔案,因此該檔案必須是來源於網路
    var worker = new SharedWorker('./worker.js');
    // 向子執行緒中傳送資料
    var obj = {
        txt:'hello SharedWorker!', 
        type: 'send'
    }
    worker.port.postMessage(obj);
} else {
    console.log('瀏覽器不支援SharedWorker子執行緒。。。');
}

worker.port.onmessage = function(res) {
    console.log('收到子執行緒的訊息:' + JSON.stringify(res.data));
}

2> 共享子執行緒worker.js
共享子執行緒必須使用 onconnect 來連線到主執行緒的埠,然後可以在onconnect event的ports屬性中獲取到與該worker相關聯的埠並向主執行緒傳送資料

下面共享接受第一個主執行緒傳送的資料並存儲,當第二個頁面主執行緒傳送獲取資料時,返回第一個主執行緒傳送的資料。

// 定義一個變數來接受主執行緒的資料
var msg = ''; 
onconnect = function(e) {
    var port = e.ports[0];
    port.onmessage = function(res) {
        if(res.data.type == 'send') {
            // 儲存主執行緒發來的資料
            msg = res.data.txt;
            // 子執行緒向主執行緒中發生訊息
            port.postMessage('已收到主執行緒的訊息。。。');
        } else if (res.data.type == 'get') {
            // 其他頁面獲取共享執行緒中的資料
            port.postMessage(msg);
        }
    }
}

3> 主執行緒index2.html
向子執行緒中傳送資料,獲取上一個執行緒儲存的資料

// 判斷瀏覽器是否支援worker執行緒
if(window.SharedWorker) {
     // 主執行緒通過new 來開啟共享子執行緒,SharedWorker建構函式的引數是一個指令碼檔案,由於SharedWorker不能讀取本地檔案,因此該檔案必須是來源於網路
     var worker = new SharedWorker('./worker.js');
     // 向子執行緒中獲取上一個執行緒儲存的資料
     worker.port.postMessage({txt:'', type: 'get'});
 } else {
     console.log('瀏覽器不支援SharedWorker子執行緒。。。');
 }

 worker.port.onmessage = function(res) {
     console.log('收到子執行緒的訊息:' + JSON.stringify(res.data));
 }

執行第一個頁面的時候返回的結果如下:
在這裡插入圖片描述

執行第二個頁面的時候就會返回第一個頁面傳送的資料 hello SharedWorker!
在這裡插入圖片描述