Web Worker爲Web內容在後臺線程中運行腳本提供了一種簡單的方法。線程能夠執行任務而不干擾用戶界面。此外,他們可使用XMLHttpRequest執行 I/O (儘管responseXML和通道屬性老是爲空)。一旦建立, 一個worker 能夠將消息發送到建立它的JavaScript代碼, 經過將消息發佈到該代碼指定的事件處理程序 (反之亦然)。 —— MDNjavascript
衆所周知,JavaScript是單線程的編程語言,也就是說,當咱們在頁面中進行一個較爲耗時的計算的JavaScript代碼時,在這段代碼執行完畢以前,頁面是沒法響應用戶操做的。也正是出於這個緣由,HTML5爲咱們提供了 Web Workers 以解決這種問題,當咱們須要在JavaScript中來進行耗時的計算或諸如此類的問題時,咱們可使用 Web Workers 在瀏覽器的後臺啓動一個獨立的 Worker 線程來專門負責這段代碼的運行,而不會阻礙後面代碼的運行。html
實例化運行一個 Worker 很簡單,咱們只須要 new 一個 Worker 全局對象便可。java
var worker = new Worker('./worker.js')
複製代碼
它接受一個 filepathname String 參數,用於指定 Worker 腳本文件的路徑。而後咱們就能夠在 worker.js 中寫下一些代碼:git
console.log('my_WOEKER:', 'srtian')
複製代碼
另外,經過URL.createObjectURL()建立URL對象,也能夠實現建立內嵌的worker:web
var myTask = ` var i = 0; var timedCount = () => { i = i+1; postMessage(i); setTimeout(timedCount, 1000); } timedCount(); `;
var myblob = new Blob([myTask]);
var myWorker = new Worker(window.URL.createObjectURL(myblob));
複製代碼
須要注意的是,傳入 Worker 構造函數的參數 URI 必須遵循同源策略。ajax
此外由於Worker線程的建立的是異步的,因此主線程代碼不會阻塞在這裏等待 worker 線程去加載、執行指定的腳本文件,而是會當即向下繼續執行後面代碼這點也須要注意。編程
當咱們實例化一個 Worker 線程後,Worker不會相互,或者與主程序共享任何做用域或資源——那會將全部的多線程編程的噩夢帶到咱們面前——取而代之的是一種鏈接它們的基本事件消息機制。所以他們須要經過基於事件監聽機制的message來進行通訊,咱們在new Worker()後悔返回一個實例對象,它包含了一個postMessage的方法,咱們能夠經過調用這個方法來給worker線程傳遞信息,咱們也能夠給這個對象監聽事件,從而在worker線程中出發事件通訊的時候能接收到數據。canvas
var worker = new worker('./worker.js')
worker.addEventListener('message', function(e) {
console.log('worker receive:', e.data )
}
worker.postMessage('hello worker,this is main.js')
複製代碼
而後在worker.js這個腳本中,咱們就能夠調用全局函數postMessage和全局的onmessage賦值來發送和監聽數據和事件了。瀏覽器
// 監聽事件
onmessage = function (e) {
console.log('WORKER RECEIVE:', e.data);
// 發送數據事件
postMessage('Hello, this is worker.js');
}
複製代碼
須要注意的是 worker 支持 JavaScript 中全部類型的數據傳遞,能夠傳遞一個 Object 數據;但這裏的數據傳遞(主要是 Object 類型)並非共享,而是複製。發送端的數據和接收端的數據是複製而來,並不指向同一個對象,此外這裏的複製不是簡單的拷貝,而是經過兩端的序列化/解序列化來實現的,通常來講瀏覽器會經過 JSON 編碼/解碼;固然,這裏的更多細節部分會由瀏覽器來處理,咱們並不須要關心這些,只須要明白兩端的數據是複製而來,互相獨立的就好了。緩存
當 worker 出現運行中錯誤時,它的 onerror 事件處理函數會被調用。它會收到一個擴展了 ErrorEvent 接口的名爲 error的事件。
該事件不會冒泡而且能夠被取消;爲了防止觸發默認動做,worker 能夠調用錯誤事件的 preventDefault() 方法。
錯誤事件有如下三個用戶關心的字段:
實際操做以下:
var worker = new Worker('./worker.js');
// 監聽消息事件
worker.addEventListener('message', function (e) {
console.log('MAIN RECEIVE: ', e.data);
});
// 也可使用 onMessage 來監聽事件:
// 監聽 error 事件
worker.addEventListener('error', function (e) {
console.log('MAIN ERROR:', e);
console.log('MAIN ERROR:', 'filename:' + e.filename + '---message:' + e.message + '---lineno:' + e.lineno);
});
// 觸發事件,傳遞信息給 Worker
worker.postMessage({
m: 'Hello Worker, this is main.js'
});
複製代碼
當咱們在不須要 Worker 繼續運行時,我就須要終止掉這個線程,這時候咱們就能夠調用 worker 的 terminate 方法:
worker.terminate()
複製代碼
worker 線程會被當即殺死,不會有任何機會讓它完成本身的操做或清理工做。
而在worker線程中,workers 也能夠調用本身的 close 方法進行關閉:
close()
複製代碼
因爲Web Workers是HTML5所提供的,所以從兼容性上來講,仍是須要注意的。總的兼容狀況以下圖所示:
圖片來源:https://caniuse.com/#feat=webworkers咱們能夠看到,雖然web worker很不錯,但若是咱們的代碼執行在較老的瀏覽器中時,是缺少支持的。但因爲worker是一個API而不是語法,所以我門仍是能夠去填補它的。
這一塊的詳情能夠去看——《你不知道的JavaScript中卷》關於 web worker 的那一節。
因爲在 Worker 線程的運行環境中沒有 window 全局對象,也沒法訪問 DOM 對象,因此通常來講咱們在這隻能執行純JavaScript的計算操做,固然1咱們那:
總的來講,Web Worker爲咱們帶來了強大的計算能力,咱們能夠加載一個JavaScript進行大量的複雜計算,而用不掛起主進程。並經過postMessage,onmessage進行通訊,這也解決了大量計算對UI渲染的阻塞問題。
Web Worker最簡單的應用應該就是用來進行後臺計算了,這對CPU密集型的場景再適合不過了。
經過使用從 canvas 中獲取的數據,能夠把圖像分割成幾個不一樣的區域而且把它們推送給並行的不一樣Workers來作計算,對圖像進行像素級的處理,再把處理完成的圖像數據返回給主頁面。
目前mvvm框架愈來愈普及,基於數據驅動的開發模式也越愈發流行,將來大數據的處理也可能轉向到前臺,所以咱們將大數據的處理交給在Web Worker也是很好的。
爲優化的網站或 web 應用的數據加載時長,咱們可使用 Web Worker 預先獲取一些數據,存儲起來以備後續使用,由於它毫不會影響應用的 UI 體驗。
因爲在主線程中每啓動一個XMLHttpRequest請求都會消耗資源,雖然在請求過程當中瀏覽器另外開了一個線程,可是在交互過程當中仍是須要消耗主線程資源;而使用worker則不會過多佔用主線程,只是啓動worker過程時比較耗資源。
參考資料: