JavaScript 學習筆記 - Web Workers

前言

本文僅是 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'
})

API 介紹

postMessage

postMessage(data, origin):工做線程向主線程傳遞數據,data 是傳遞的數據,origin 用來設置跨域相關的東西,這裏不作介紹。

terminate

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

onmessage:用來接收工做線程傳遞給主線程的消息。

onerror

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 的很不安全的。

總結

知識點很少,對於通常的使用,應該足夠了。

相關文章
相關標籤/搜索