WebWorker

瀏覽器執(zhí)行環(huán)境是單線程的,一旦出現(xiàn)【主線程】耗時操作,就會造成瀏覽器卡死,用戶點擊沒響應(yīng)等情況。

Web Worker 可以創(chuàng)建一個獨立于主線程運行的子線程。可以將一些【可能會阻塞主線程的操作】,丟在 Worker 里去單獨執(zhí)行。

那為什么平時都沒有意識到主線程阻塞這個問題呢?

因為下大多數(shù)情況下,我們不太關(guān)心瀏覽器主線程是否會被阻塞,因為同步代碼執(zhí)行一般都很快,慢的I/O、異步請求、定時器等操作,瀏覽器默認(rèn)就幫我們異步操作了(變成宏、微任務(wù)了)。

比如:

  • 異步請求
  • 定時器
  • 宏、微任務(wù)等。

阻塞主線程 - 一般不會出現(xiàn)

事實上,一般項目開發(fā)中,很難會用阻塞主線程的業(yè)務(wù)邏輯代碼出現(xiàn)。 但是為了驗證這個問題,這里可以模擬一個非常尷尬的場景。

// 創(chuàng)建一個 sleep 函數(shù),模擬主線程阻塞的情況
function sleep (wait = 5000) {
    let now = new Date()
    while (new Date() - now < wait) { }
}
sleep() // 阻塞主線程
document.addEventListener.call(btn, "click", function () {
    alert('點我有反應(yīng)嗎?')
})

我們會在瀏覽器上放一個按鈕,并給按鈕綁定點擊事件。

但由于 sleep 耗時 5 秒鐘,在此過程中,主線程就阻塞了。

sleep.gif

可以發(fā)現(xiàn),由于主線程被阻塞,瀏覽器都無法正常渲染了,都出現(xiàn)了黑屏。 點擊按鈕也半天沒反應(yīng)。


使用 Worker 解決主線程耗時造成的阻塞問題

可以將主線程一些耗時的【同步】操作,丟給 Worker 來處理,將耗時操作丟在子線程中,這樣主線程就不會被阻塞,就正常處理渲染,處理用戶點擊,異步回到等。

WebWorker 的作用,就是為了 JavaScript 創(chuàng)建多線程環(huán)境,允許主線程創(chuàng)建 Worker 子線程,將一些【可能會阻塞主線程】的任務(wù)分配給 worker 子線程去處理。兩者互不干擾。等子線程處理完成之后,在通過消息的機制把處理結(jié)果返回給主線程即可。充分利用多線程的優(yōu)勢。

Worker 線程畢竟占據(jù)的一個操作系統(tǒng)的線程資源,在 Worker 的任務(wù)執(zhí)行完畢之后,即可將其關(guān)閉,釋放操作系統(tǒng)線程資源。


Worker 使用說明和 API

使用說明

  • 同源限制

分配給 worker 線程的腳本,必須和主線程腳本同源。(否則無法創(chuàng)建 worker,且雙方無法通信)

  • DOM限制

Worker 工作在子線程,和主線程不太一樣。所以并無法操作 DOM \ BOM 等 API。(純數(shù)據(jù)處理)

  • 全局對象限制

Worker 全局對象不是 window,所以一些 window 上的全局屬性和方法也無法訪問。(但可以訪問 NavigatorLocation接口)

  • 通信限制

由于 Worker 單獨運行在一個子線程,所以和主線程通信使用發(fā)布、訂閱的消息機制完成。

  • 腳本限制

可以在 Worker 中使用 XMLHttpRequest 來發(fā)送異步請求。

  • 運行環(huán)境限制

Worker 不能運行在 file:// 協(xié)議下。(不能直接右鍵打開)


API

Worker 的 API 十分簡單,和 iframe 通信 API 類似。

主線程

// 在主線程中,使用 `new Worker` 構(gòu)造函數(shù),來創(chuàng)建一個 `Worker` 實例。
const worker = new Worker('worker.js',{name: 'worker'})
// 主線程中,向子線程 worker 發(fā)送數(shù)據(jù) 
worker.postMessage(data)
// 主線程中,監(jiān)聽子線程 worker 回發(fā)的數(shù)據(jù)
worker.onMessage = (data) => {
    console.log('來自子線程的數(shù)據(jù)',data)
}
// 主線程中,監(jiān)聽 worker 錯誤
worker.onerror = (err) => {}

// 主線程關(guān)閉 worker 子線程
worker.close()

子線程 worker.js

//在 worker 線程中監(jiān)聽主線程發(fā)送過來的數(shù)據(jù)
self.onmessage = (data) => {
    console.log('主線程發(fā)送過來的數(shù)據(jù)',data)
}
// 在 worker 中,向主線程發(fā)送數(shù)據(jù)
self.postMessage(data)
// 在 worker 中監(jiān)聽錯誤
self.onerror = (err) => {}

// 在 worker 中關(guān)閉自己
self.close()

利用 Worker 解決上述主線程阻塞問題

// 在瀏覽器主線程中..
// 定義異步事件,worker 限制耗時操作不會阻塞主線程
document.addEventListener.call(btn, "click", function () {
    alert('點我有反應(yīng)嗎?')
  })
  // 主線程創(chuàng)建 worker
const worker = new Worker('./worker.js', { name: 'my-worker' })
// 主線程給 worker 子線程發(fā)送數(shù)據(jù)
worker.postMessage({ id: 1, name: 'gqs' })
// 主線程注冊子線程的 postmessage 數(shù)據(jù)回調(diào)
worker.onmessage = ({ data }) => {
    console.log('來自子線程 worker 的數(shù)據(jù)', data)
  }
// 在 worker.js 子線程中

console.log(self.name)

self.onmessage = function ({ data }) {
  console.log('接受到了來自主線程的數(shù)據(jù):', data)
  sleep(10000) // 耗時 10s
  self.postMessage({ id: 1, name: 'gqs' })
}

self.onerror = function (err) {
  // worker 線程發(fā)生了錯誤!
  throw new Error(err)
}

// 模擬會阻塞主線程的耗時操作.
function sleep (wait = 5000) {
  let now = new Date()
  while (new Date() - now < wait) { }
}

我們將【會阻塞主線程】的耗時操作,丟在 worker 中去單獨處理后,在查看效果。

worker 解決主線程阻塞.gif

總結(jié)

一般情況下,你不會用到 Worker ,因為瀏覽器主線程一般很少會出現(xiàn)很復(fù)雜從而導(dǎo)致阻塞的操作。默認(rèn)的耗時操作,都會瀏覽器默認(rèn)處理為宏、微任務(wù)了。

當(dāng)遇到了類似上述那種,在主線程同步環(huán)境下造成阻塞的問題,可以使用 worker 來創(chuàng)建一個子線程進行處理,提高用戶體驗。

碼云

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、什么是 頁面阻塞?怎么解決? 頁面阻塞: 大多數(shù)瀏覽器是使用單線程處理 UI更新 和 JavaScript 運...
    淺秋_6672閱讀 3,268評論 0 3
  • 一,介紹與需求 1.1,介紹 Web Worker可以為JavaScript創(chuàng)建多線程,且Web Worker 是...
    金色888閱讀 391評論 0 0
  • 【W(wǎng)ebworker】 注:必須要在服務(wù)器環(huán)境。 什么是webworker?Web Worker為Web應(yīng)用程序提...
    虛幻的銹色閱讀 15,346評論 0 11
  • 基本概念 JS單線程:我們都知道JavaScript它是一個單線程的語言,同一時間只能做一件事。比如:在瀏覽器中,...
    前白閱讀 161評論 0 0
  • Web Worker JavaScript 語言采用的是單線程模型,也就是說,所有任務(wù)只能在一個線程上完成,一次只...
    johe_jianshu閱讀 1,176評論 0 0

友情鏈接更多精彩內(nèi)容