前言
大家好,我是林三心,用最通俗易懂的話講最難的知識點是我的座右銘,基礎是進階的前提是我的初心,今天給大家講一個你們既熟悉又陌生的東西——Web Worker
為什麼js是單執行緒語言?
先給大家說說JavaScript為啥是一個單執行緒語言呢?我們們都知道,JavaScript是一門以前端為主的語言,而前端的舞臺就是瀏覽器,而瀏覽器通過什麼取悅使用者呢?通過的是一個一個的DOM節點組成的頁面。所以說,JavaScript最終的目的都要以頁面展現的質量為目的。
而JavaScript設計為單執行緒語言也是為了頁面,我們們假設JavaScript是多執行緒語言,如果有一天,執行緒1在修改DOM節點,同時執行緒2也在修改同一個DOM節點,那請問頁面應該聽誰的?這就會造成衝突,而這在使用者面前可是不被允許的,所以JavaScript設計成了單執行緒語言,想要操作啥,都得按著順序來。
Web Worker?
背景
剛剛也說了JavaScript是單執行緒語言,這也造成了許多問題。不知道大家平時開發的時候,有沒有遇到這樣的事:處理一個超級大的資料,導致整個程式碼的邏輯被阻塞了一段時間
說說我遇到的場景吧:
- 1、大檔案切片上傳配hash時,需處理一小段時間
- 2、樹形資料前端處理時,需要處理一小段時間
而這可能導致了什麼假死
問題呢? - 1、頁面渲染的阻塞
- 2、後面程式碼執行的阻塞
是什麼?
Web Worker
為了解決瀏覽器 假死
這個問題而孕育而生的一項新技術。它是多執行緒模型,也是基於宿主。它屬於JavaScript執行緒中的一個子執行緒,它完全受主執行緒控制,但是在 Web Worker
裡面是不能操作DOM的。需要保證DOM的唯一性,因此主的基調不能改變,但是需要有一個新的執行緒來分擔繁雜的計算任務,這個也就是 Web Worker
相容性:
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('處理資料時間')
我們們可以看看處理資料花了多少時間:
而圖片的渲染也是在這個時間之後(渲染圖片也需要一定時間,所以有差值),這也說明了剛剛的資料處理,阻塞了頁面的渲染:
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('處理資料時間')
}
效果
我們再來看看程式碼和渲染的效果,跟剛才一開始的對比下:
圖片渲染也沒有被阻塞:
取消程式
可以使用 terminate
方法結束程式
worker.onmessage = (e) => {
// 報錯時馬上終止指定worker程式
worker.terminate()
console.log(e.data)
}
個人理解
其實 Web Worker
本質上並沒有改變 JavaScript單執行緒
這一事實,它藉助的是 瀏覽器的多執行緒
結語
我是林三心,一個熱心的前端菜鳥程式設計師。如果你上進,喜歡前端,想學習前端,那我們們可以交朋友,一起摸魚哈哈,摸魚群,加我請備註【思否】