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://),它所載入的指令碼,必須來自網路。
基本使用–專用執行緒
專用執行緒會隨當前頁面的關閉而結束,所以專用執行緒只能被建立它的頁面訪問
- 主執行緒
// 判斷瀏覽器是否支援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();
})
- 子執行緒
// 通過監聽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!