WebWorker 一定程度上可以算得上是瀏覽器中的多線程技術了,在項目中適當使用 Worker 來做一些耗時的操作能大大提高頁面整體流暢度。 Worker的使用也是非常簡單的,通過向 Worker 構造函數傳遞需要在worker中運行的文件路徑作為參數,就可以使得對應的文件運行在worker線程。 ...
WebWorker 一定程度上可以算得上是瀏覽器中的多線程技術了,在項目中適當使用 Worker 來做一些耗時的操作能大大提高頁面整體流暢度。
Worker的使用也是非常簡單的,通過向 Worker 構造函數傳遞需要在worker中運行的文件路徑作為參數,就可以使得對應的文件運行在worker線程。
Worker線程中沒有 window 對象,也沒有 document 對象。既不能操作也不能創建 DOM。而且 worker 線程和主線程只能通過消息機制來通信。
下麵是一個 WebWorker 的簡單用法:
首先需要創建一個 Worker 實例:
var worker = new Worker('worker.js');
在 worker.js 中寫下如下代碼:
1 console.log('Hello world');
然後 worker.js 就會在 worker 線程中運行,這也就意味著這裡的代碼不管是什麼,基本上可以認為對主線程(也就是瀏覽器線程)沒有任何影響。雖然實際上電腦跑的東西越多性能越差,但至少主線程不會被阻塞。
無法跟主線程交互的代碼用處非常有限,當然,你可以繞過去,直接大家都走伺服器端結合 WebSocket 來實現跟主線程,但 WebWorker 本身能跟主線程通過消息機制來交互確實會更方便些,如果再允許提交對於 DOM 的操作就更好了。
WebWorker 通過 postMessage 來發送消息,通過 message 事件來接受接收消息。其中發送的數據就在 event.data 中。
比如上面的代碼,由於 worker.js 是通過主線程的代碼載入的,所以執行順序定然晚於主線程的代碼執行,當 worker.js 中的代碼執行後,可以通過向主線程發送一個消息,告訴主線程一切就緒,可以開始開始正常交互了.
這裡需要知道的就是 在 worker 中沒有 window 實例,也沒有全局的 this,但是卻有著 WorkerGlobalScope 也就是 self,當前 worker 自己。
1 self.postMessage('ready');
在主線程中通過事件處理程式接收消息
1 worker.addEventListener('message', function (event) { 2 console.log(event.data); 3 });
另外,所有跟 worker 線程交互的代碼也最好在收到 ·ready· 這個消息之後進行。因為此時 worker 線程已經就緒,而且可以在發送 ready 消息之前把必備的準備工作做好。
還有就是消息不要真的就發送簡單的字元串,除非系統裡面確實就是這種需求,最好設計下數據結構,採用統一的方式來做消息交互,比如類似下麵這樣或者別的方式都行:
{ cmd: '', payload: ... }
要進行錯誤處理,在主線程和在 worker 中做法很相似,都是添加 “error”事件處理程式,不同的是用 worker 實例還是 WorkerGlobalScope 也就是 self。
1 worker.addEventListener('error', function (event) { 2 console.log('在主線程內監聽 worker 實例的錯誤'); 3 }); 4 5 self.addEventListener('error', function (event) { 6 console.log('在 worker 線程內監聽當前 worker 的錯誤'); 7 });
類似在 html 文檔中可以使用 <script> 標記導入外部腳本,在 worker 裡面也可以導入外部腳本,用法如下:
1 importScripts('script1.js', 'script2', ....); // 可以導入一個到多個,省略號不是代碼,這行只算是偽代碼
最後用完了 worker 就可以把它關閉了,在主線程中用 terminate,在 worker 線程中直接用用 close 就可以了,用不到時就應該即使關閉,多少能省點系統資源。
1 worker.terminate(); // 在主線程中關閉當前 worker 2 self.close(); // 在 worker 中關閉自己