Web Worker:靚仔,要不要試試開個「子執行緒」耍耍?很快的哦!

Sunshine_Lin發表於2022-01-18

前言

大家好,我是林三心,用最通俗易懂的話講最難的知識點是我的座右銘,基礎是進階的前提是我的初心,今天給大家講一個你們既熟悉又陌生的東西——Web Worker

為什麼js是單執行緒語言?

先給大家說說JavaScript為啥是一個單執行緒語言呢?我們們都知道,JavaScript是一門以前端為主的語言,而前端的舞臺就是瀏覽器,而瀏覽器通過什麼取悅使用者呢?通過的是一個一個的DOM節點組成的頁面。所以說,JavaScript最終的目的都要以頁面展現的質量為目的。

1641539889(1).jpg

而JavaScript設計為單執行緒語言也是為了頁面,我們們假設JavaScript是多執行緒語言,如果有一天,執行緒1在修改DOM節點,同時執行緒2也在修改同一個DOM節點,那請問頁面應該聽誰的?這就會造成衝突,而這在使用者面前可是不被允許的,所以JavaScript設計成了單執行緒語言,想要操作啥,都得按著順序來。

Web Worker?

背景

剛剛也說了JavaScript是單執行緒語言,這也造成了許多問題。不知道大家平時開發的時候,有沒有遇到這樣的事:處理一個超級大的資料,導致整個程式碼的邏輯被阻塞了一段時間

1641539197(1).png

說說我遇到的場景吧:

  • 1、大檔案切片上傳配hash時,需處理一小段時間
  • 2、樹形資料前端處理時,需要處理一小段時間
    而這可能導致了什麼 假死 問題呢?
  • 1、頁面渲染的阻塞
  • 2、後面程式碼執行的阻塞

是什麼?

Web Worker 為了解決瀏覽器 假死 這個問題而孕育而生的一項新技術。它是多執行緒模型,也是基於宿主。它屬於JavaScript執行緒中的一個子執行緒,它完全受主執行緒控制,但是在 Web Worker 裡面是不能操作DOM的。需要保證DOM的唯一性,因此主的基調不能改變,但是需要有一個新的執行緒來分擔繁雜的計算任務,這個也就是 Web Worker

1641543329(1).jpg

相容性:

image.png

Web Worker 有以下特點:

  • 1、一旦新建,則不會被主執行緒打斷。即便是主執行緒卡死,Web Worker仍然執行中
  • 2、Web Worker也受同源策略限制,同源網頁才能訪問
  • 3、不能操作和訪問DOM,前面也說了多執行緒操作DOM容易造成衝突,所以禁止
  • 4、不能使用全域性互動方法(alert、confirm等),其他全域性方法基本可以使用
  • 5、不能讀取本地檔案(其實瀏覽器本身就禁止JavaScript讀取本地檔案,出於安全考慮)
  • 6、worker執行緒與主執行緒不共享作用域與資源
  • 7、Web Worker有兩種:

    • Dedicated Web Worker :專用執行緒,只能在一個網頁裡使用這個執行緒
    • Shared Web Worker :共享執行緒,可以在多個同源的網頁中共享,也是跨頁面通訊的手段之一

使用Web Worker

場景

為了讓大家看到 Web Worker 的效果,我新建了幾個檔案

// index.html
<script src="./index.js"></script>
<img src="./頭像.jpg" alt="">
// index.js

console.time('處理資料時間')

// 模擬資料處理
function handleData(num) {
  for (let i = 0; i < num; i++) {
    let str = ''
    while (str.length < 150) {
      str += '哈'
    }
  }
}

handleData(2000000)
console.timeEnd('處理資料時間')

我們們可以看看處理資料花了多少時間:

1641542381(1).jpg

而圖片的渲染也是在這個時間之後(渲染圖片也需要一定時間,所以有差值),這也說明了剛剛的資料處理,阻塞了頁面的渲染:

1641547112(1).jpg

Web Worker基本使用

專案開發中用 Dedicated Web Worker ,比較多,所以講講這個的基本使用吧

改寫一下 index.js 中的程式碼

// index.js

// 例項一個 Woeker ,並傳入目標檔案路徑,這個目標檔案將會生成一個worker執行緒
const worker = new Worker("data.js")
// 使用 postMessage 傳輸資訊到目標檔案
worker.postMessage(2000000)
// 使用 onmessage 接受資訊
worker.onmessage = (e) => {
  console.log(e.data)
};
// 使用 onerror 進行目標檔案,也就是指定worker執行緒發生錯誤時的回撥
worker.onerror = function (e) {
  console.log("error at " + e.filename + ":" + e.lineno + e.message)
};

然後我們建立一下目標檔案 data.js ,他將會生成一個 worker執行緒

// 使用 importScripts 進行檔案的引用,可引用 url、本地js檔案
importScripts('xxxxxxx')
// importScripts('xxxxxxx', 'xxxxxxxx') 也可以傳多個

// 模擬資料處理
function handleData(num) {
  for (let i = 0; i < num; i++) {
    let str = ''
    while (str.length < 150) {
      str += '哈'
    }
  }
}

onmessage = async (e) => {
  console.time('處理資料時間')
  const res = handleData(e.data)
  postMessage('處理完了')
  console.timeEnd('處理資料時間')
}

效果

我們再來看看程式碼和渲染的效果,跟剛才一開始的對比下:

1641546740(1).jpg

圖片渲染也沒有被阻塞:

1641546979(1).jpg

取消程式

可以使用 terminate 方法結束程式

worker.onmessage = (e) => {
  // 報錯時馬上終止指定worker程式
  worker.terminate()
  console.log(e.data)
}

個人理解

其實 Web Worker 本質上並沒有改變 JavaScript單執行緒 這一事實,它藉助的是 瀏覽器的多執行緒

結語

我是林三心,一個熱心的前端菜鳥程式設計師。如果你上進,喜歡前端,想學習前端,那我們們可以交朋友,一起摸魚哈哈,摸魚群,加我請備註【思否】

image.png

相關文章