接下來咱們開始講解一個使用 Web Worker 運算斐波那契數列的例子。項目地址javascript
首先,咱們須要經過Worker()構造器建立worker實例,其只接受一個參數,該參數則是線程腳本的地址,該地址必須符合同源策略。html
能夠查看代碼,我再使用同目錄下的 dedicate-worker.js 文件建立了一個 Worker 對象出來,當初始化完成後,瀏覽器後臺線程就回運行該腳本了。java
var worker = new Worker('dedicate-worker.js');
複製代碼
那主線程(頁面)和後臺線程的 Worker 之間是如何通訊的呢?這裏就要 postMessage 方法了。git
worker.postMessage(message, [transfer]);
複製代碼
postMessage 方法接受兩個參數,第一個就是 worker 之間傳遞的數據信息,第二個參數是一個數組,用來轉讓對象全部權。github
/* html 部分 <div class='normal'> <button onclick='normalPost(34)'>34</button> <button onclick='normalPost(42)'>42</button> </div> */
// js 部分
function normalPost(num) {
worker.postMessage(num);
}
複製代碼
上述代碼中,當咱們點擊對應的按鈕時候,會發送數字到對應的到子線程。後臺子進程須要監聽 onmessage 事件,才能接受主進程發送來的數據。而該事件接受一個 MessageEvent 對象,其中 data 屬性就是主進程傳入的數據。web
// dedicate-worker.js
// 斐波那契數列
function fabonacci(n) {
if (n === 0) {
return 0;
}
if (n === 1) {
return 1;
}
return fabonacci(n - 1) + fabonacci(n - 2);
}
onmessage = function(messageEvent) {
var str = messageEvent.data;
str = typeof str === 'number' ? String(str) : str;
switch (str) {
// ...
case (str.match(/[0-9]/) || {}).input:
var result = fabonacci(Number(str));
postMessage({msg: str+'的斐波那契數列是:' + result, code: 'fobo'});
break;
default:
postMessage({msg: 'hi, bro~ 慢慢想一下~', code: ''});
break;
}
}
複製代碼
上述代碼中,咱們經過 onmessage 監聽獲取主線程傳輸進來的數據,若是對應的數據運算完成事後,直接調用 postMessage 方法將對應的結果傳輸出去,注意在子進程的腳本中,由於全局做用域已經改變的緣由是能夠直接調用 postMessage 的方法,可是在主進程中是不能夠的,是須要指定對應的wroker對象調用的。chrome
回到主進程代碼,在這裏咱們也只要讓對應的 worker 監聽 onmessage 事件便可接受由子線程傳遞過來的數據。數組
worker.addEventListener('message', (e) => {
var res = e.data;
switch (e.data.code) {
default:
app.textContent = res.msg;
break;
}
// ...
});
複製代碼
由於 Worker 仍是比較消耗資源的,因此當沒有用的時候,能夠選擇關閉,即調用 terminate 方法便可。瀏覽器
var worker = new Worker('dedicate-worker.js');
worker.terminate();
複製代碼
咱們實現一個多個 tab 共享部分數據效果。大概這樣的效果: app
Shared Worker 建立的方法相似於 dedicated Worker,調用 SharedWorker 構造器,語法以下:
new SharedWorker(aURL, name);
複製代碼
其中 aURL 表示腳本的地址,name 表示子線程的名字,同名的線程是能夠共享的噢,但依舊要遵循同源策略。在咱們的項目中,咱們是這樣建立的:
var shareWorker = new SharedWorker('share-worker.js', 'sharedWork');
複製代碼
一樣的咱們能夠經過 postMessage 方法將信息傳遞給子進程,但由於 SharedWorker 實現的緣由不一樣,咱們須要經過實例的 port 屬性去調用 postMessage。
input.addEventListener('change', (e) => {
shareWorker.port.postMessage({value: e.target.value, type: 'write'});
})
複製代碼
上述代碼中,咱們經過監聽輸入框的 change 事件觸發主線程傳遞信息給子線程。而子線程由於做用域的不一樣,對應的鏈接主線程方式稍有不一樣,咱們經過監聽 onconnect 接通主線程,而後經過接受參數的 ports 屬性獲取到 MessagePort
對象,這時候即可以使用 onmessage 和 postMessage 處理和傳遞數據了。
// ...
onconnect = function (messageEvent) {
messageEvent.source.addEventListener('message', (event) => {
swicthByTypeCode(event.data);
})
source.start();
}
// ...
複製代碼
上述代碼,主要是子線程鏈接主線程,並讓 MessagePort 對象監聽 message 事件,但注意若使用 addEvevntListener 監聽的時候,須要自行 start 方法啓動。
調試 Dedicated Worker 能夠直接在控制檯進行調試,惟獨調試 SharedWorker 的時候須要進入 chrome://inspect/#workers 點開 inspect 進行調試。
看到了最熟悉的界面,就能夠 debugger 調試了。上述僅僅描述了簡單的用法,並沒有涉及某些高級用法,如 importScripts 的應用、錯誤處理機制等。其實上文有不斷的說起到 Worker 的做用域和 window 的做用域是不一樣的,那接下來咱們看看他們究竟是什麼樣子哩?