開啟 JS 的 “多線程”,三分鐘掌握 Web Worker。面試必備!
Hello,大家好,我是 Sunday
這段時間有不少同學在面試中遇到了 web worker 的問題。所以今天咱們就通過這篇文章,把 web worker 搞明白!
Web Worker 到底是什么?
因為 JS 是單線程(主線程)的,這意味著它一次只能做一件事。當在主線程上運行耗時較長的任務時,那么 Web 應用可能會卡住或需要一段時間才能加載。如下偽代碼:
<div class="box">hello</div>
for (let i = 0; i < 1000000; i++) {
console.log(i)
}
document.querySelector('.box').innerHTML = '程序員Sunday'
而 web worker 就可以解決掉卡頓的問題。
web worker 可以在 “后臺” 獨立執行任務,類似于開啟了一個 “子線程”,可以在不影響主線程的前提下,完成對應的計算。
如下基礎代碼(暫時不需要關心什么是 slef、postMessage 或者 onmessage):
// worker.js
self.onmessage = () => {
for (let i = 0; i < 1000000; i++) {
console.log(i)
}
}
// index.html
<script>
const worker = new Worker('./worker.js')
worker.postMessage(1)
document.querySelector('.box').innerHTML = '程序員Sunday'
</script>
它主要具備以下四個特點:
- 并行執行:Web Worker 允許在不同線程中并行處理任務,不會干擾主線程的執行。這對于需要大量計算或需要處理大量數據的應用特別有用。
- 不共享全局對象:每個 Web Worker 都有自己的全局上下文(self),并且不能直接訪問主線程的 DOM 或其他全局對象。它們通過消息傳遞來與主線程或其他 Web Workers 進行通信。
- 線程安全:由于 Web Workers 在自己的線程中運行,并且沒有直接訪問共享內存的能力,這減少了多線程編程中的常見問題(如:競態問題)。
- 消息傳遞機制:主線程和 Web Worker 之間通過 postMessage 和 onmessage 事件來進行數據交換。主線程使用 worker.postMessage() 發送消息,Web Worker 使用 self.onmessage 處理消息。
明確好了它的特點之后,我們來逐步解析下對應的代碼邏輯。
Web Worker 代碼解析
想要使用 Web Worker,那么需要先明確 一個變量、一個構造、兩個方法:
變量 self
類似于 window。因為 Web Worker 在一個不同的全局上下文中運行,所以不是我們熟悉的 window 對象。而是使用 self 來代表全局上下文
構造函數 Worker
想要使用 Web Worker 那么必須要生成 Worker 實例。該構造函數接收 一個JS文件的路徑。該路徑就是書寫 Web Worker 代碼的位置
方法一 onmessage
self 的常用方法之一,用來監聽 worker 事件啟動。被 實例.postMessage 觸發
方法二 postMessage
觸發 self.onmessage 的方法。可以理解為 “啟動器”。該方法 必須 接收一個參數
Web Worker 的注意事項
使用 Web Worker 時,有兩個注意事項:
- 無法操作 DOM: DOM 的操作必須要在主線程中進行。因為 Web Worker 是單獨開辟了線程,所以無法進行 DOM 操作
- Handle Errors: Web Worker 中始終包含錯誤處理來捕獲任何問題。