本文僅是 Web Workers 的入門科普文章,不涉及太瑣碎的知識點。javascript
咱們知道,在 Web Workers 出來以前,JavaScript 是單線程的。即便是 setTimeout
之類的看似多線程的函數,實際上也是單線程執行的。css
有時,咱們須要在瀏覽器執行一個比較耗時的計算:html
function count() { let i = 0 let sum = 0 for (let j = 0; j < 100; j++) { for (let i = 0; i < 100000000; i++) { sum += i } } return sum }
若是直接在瀏覽器執行這段代碼,會把瀏覽器卡死。對於這類耗時的計算,能夠經過多線程來解決。java
多線程的重要性不言而喻。而工做線程(Web Workers),就是 JavaScript 的多線程解決方案。web
建立工做線程很簡單,只要新建一個 Worker
對象就能夠了。api
css-demo/web-worker.html
:跨域
let worker = new Worker('worker.js')
這段代碼建立了一個工做線程,用來執行 worker.js
的代碼。咱們能夠在 worker.js
執行比較耗時的計算。瀏覽器
咱們能夠寫一個簡單的工做線程代碼:安全
css-dmeo/worker.js
:服務器
console.log('hello world')
運行 css-demo/web-worker.html
,能夠看到控制檯輸出:
Failed to construct 'Worker': Script at 'file://xxx/javascript-demo/worker.js' cannot be accessed from origin 'null'
這是由於跨域的緣由,致使代碼執行失敗。咱們能夠建立一個服務器環境(推薦 Http-server)來打開 HTML。
能夠看到控制檯輸出:
hello world。
一般咱們在工做線程完成計算後,須要將計算結果傳回給主線程。咱們能夠經過 postMessage
方法把數據傳給主線程。
web-worker-message.js
:
postMessage('hello world')
主線程註冊 onmessage
回調函數,經過 event.data
接收工做線程傳遞過來的數據。
web-worker-message.html
:
let worker = new Worker('web-worker-message.js') // 設置回調函數,接收 worker 傳遞過來的數據 worker.onmessage = function(event) { console.log(event.data) }
執行後,控制檯輸出:
hello world
固然,咱們也能夠傳遞其餘類型的數據。好比,要傳遞多個數據時,能夠先構造個對象,再傳遞過去。
postMessage({ data1: 'hello', data2: 'world' })
postMessage(data, origin)
:工做線程向主線程傳遞數據,data
是傳遞的數據,origin
用來設置跨域相關的東西,這裏不作介紹。
terminate()
函數用來結束工做線程。
web-worker-terminate.html
:
let worker = new Worker('web-worker-terminate.js') worker.terminate()
web-worker-terminate.js
:
setTimeout(function () { console.log('hello') }, 1000)
運行後,等了會兒,和預期的同樣,控制檯沒有任何輸出。
onmessage
:用來接收工做線程傳遞給主線程的消息。
onerror
用來處理線程錯誤。
web-worker-onerror.html
:
let worker = new Worker('web-worker-onerror.js') worker.onerror = function(e) { // 打印錯誤消息 console.log(e.message) }
web-worker-onerror.js
:
undefinedFunction()
控制檯輸出:
Uncaught ReferenceError: undefinedFunction is not defined
除了普通的異常錯誤,404 等 HTTP 請求錯誤時也能回調。
let worker = new Worker('no-exist-url.js') worker.onerror = function(e) { // 打印錯誤消息 console.log(e.message) }
控制檯輸出:
undefined
若是你試過在工做線程中執行 alert
函數,就會執行出錯。
Uncaught ReferenceError: alert is not defined
這是由於在工做線程中,JavaScript 代碼執行的上下文(Runtime Context)並非 Window 對象。
你能夠在工做線程中執行:console.log(Window)
,控制檯會輸出:
Uncaught ReferenceError: Window is not defined
咱們能夠經過 console.log(this)
把工做線程中當前上下文對象打印出來。
輸出的不是 Window
對象。因爲上下文的不一樣,工做線程的 JavaScript API 會和之前的用法有點不同。最大的區別在於:工做線程中不能操做 DOM。
工做線程的職責在於處理數據,而後把處理完成的數據傳給主線程,主線程再根據數據更新界面。
可能有人以爲這樣很麻煩,若是你作過多線程界面開發(好比 Android),應該清楚這樣作的緣由:在多個線程同時更新 UI 的很不安全的。
知識點很少,對於通常的使用,應該足夠了。