作者:刮刮樂打工仔
https://juejin.cn/post/7439918857492660259
前提:什么是線程???
線程(英語:thread)是操作系統(tǒng)[1]能夠進行運算調(diào)度[2]的最小單位。它被包含在進程[3]之中,是進程[4]中的實際運作單位。一條線程指的是進程[5]中一個單一順序的控制流,一個進程中可以并發(fā)多個線程,每條線程并行執(zhí)行不同的任務(wù)。
線程是獨立調(diào)度和分派的基本單位。
同一進程中的多條線程將共享該進程中的全部系統(tǒng)資源,如虛擬地址空間,文件描述符[6]和信號處理[7]等等。但同一進程中的多個線程有各自的調(diào)用棧[8](call stack),自己的寄存器環(huán)境(register context),自己的線程本地存儲(thread-local storage)。
JavaScript單線程
JavaScript設(shè)計成單線程目的:為了防止多個線程同時操作DOM,帶來渲染沖突問題。
但是遇見大量計算會使頁面卡頓,用戶體驗不佳
就引出本篇的主題Web Worker
??Web Worker??
Web Worker
允許我們在 js 主線程之外開辟新的 Worker 線程。 因為是獨立的線程,Worker 線程與 js 主線程能夠同時運行,互不阻塞。 如果有大量運算任務(wù)時,可以把運算任務(wù)交給 Worker 線程去處理,當(dāng) Worker 線程計算完成,再把結(jié)果返回給 js 主線程。
js主線程只用專注處理業(yè)務(wù)邏輯,Worker處理大量復(fù)雜計算,從而減少了主線程阻塞 時間,提高運行效率和提升用戶體驗。
Web Worker用法
const worker = new Worker(path, options);
path
js腳本的路徑地址(遵守同源策略),否則會拋出SECURITY_ERR
類型錯誤
type
worker 類型。該值可以是 classic
或 module
。 默認值 classic
credentials
worker憑證。該值可以是 omit
, same-origin
,或 include
。默認值 omit
(不要求憑證)
主線程與Worker參數(shù)之間參數(shù)傳遞
index.html
const myWorker = new Worker('/worker.js');
myWorker.addEventListener('message', e => {
console.log(e.data);
});
myWorker.postMessage('這里是主線程');
worker.js
// self是worker的全局對象,它繼承了WorkerGlobalScope的屬性和方法
self.addEventListener('message', e => {
console.log(e.data);
self.postMessage('這里是worker線程');
});
控制臺輸出結(jié)果
線程監(jiān)聽
index.html
const myWorker = new Worker('/worker.js');
myWorker.addEventListener('error', err => {
console.log(err.message);
});
myWorker.addEventListener('messageerror', err => {
console.log(err.message)
});
work.js
self.addEventListener('error', err => {
console.log(err.message);
});
self.addEventListener('messageerror', err => {
console.log(err.message);
});
線程關(guān)閉
index.html
const myWorker = new Worker('/worker.js');
myWorker.terminate(); // 關(guān)閉worker
worker.js
self.close();
線程內(nèi)部引用其它文件
worker 線程中利用 importScripts()
方法加載js文件,此方法加載的js文件不受同源策略約束
utils.js
const fn = ()=>{
console.log("hello, world")
}
worker.js
// 使用方法:importScripts(path1, path2, ...);
importScripts('./utils.js
// 直接使用
fn()
如果你的utils是ESModule, 生成Worker實例的時候,type指定類型為module, 這個時候你的word.js需把頂級對象self暴露出去
index.html
const worker = new Worker('/worker.js', {
type: 'module' // 指定 worker.js 的類型
});
worker.js
...
export default self; // 只需把頂級對象self暴露出去即可
傳參注意事項
??SharedWorker??
SharedWorker
接口代表一種特定類型的 worker,可以從幾個瀏覽上下文中訪問,例如幾個窗口、iframe 或其他 worker。它們實現(xiàn)一個不同于普通 worker 的接口,具有不同的全局作用域,`SharedWorkerGlobalScope`[9] 。
實現(xiàn)多頁面通信
a.html
const worker = new SharedWorker('calculator.js');
worker.port.onmessage = function(event) {
console.log(event.data); // 接收SharedWorker返回的結(jié)果
};
worker.port.postMessage({ type: 'add', operands: [2, 3] }); // 向SharedWorker發(fā)送消息
b.html
const worker = new SharedWorker('calculator.js');
worker.port.onmessage = function(event) {
console.log(event.data); // 接收SharedWorker返回的結(jié)果
};
worker.port.postMessage({ type: 'multiply', operands: [4, 5] }); // 向SharedWorker發(fā)送消息
calculator.js
const ports = [];
self.onconnect = function(event) {
const port = event.ports[0];
ports.push(port);
port.onmessage = function(event) {
const message = event.data;
const result = calculate(message.type, message.operands); // 執(zhí)行計算任務(wù)
ports.forEach(port => port.postMessage(result)); // 將結(jié)果發(fā)送給所有連接的頁面
};
};
function calculate(type, operands) {
if (type === 'add') {
return operands.reduce((a, b) => a + b, 0);
} elseif (type === 'multiply') {
return operands.reduce((a, b) => a * b, 1);
}
}
??Web Worker(性能優(yōu)化)總結(jié)??
- 多線程處理:Web Worker 允許在獨立的線程中運行 JavaScript 代碼,這樣可以充分利用多核處理器和提高性能。
- 避免阻塞主線程:通過將一些密集計算或長時間運行的任務(wù)放在 Web Worker 中,可以避免阻塞主線程,提高頁面的響應(yīng)性。
- 異步處理:Web Worker 提供了一個與主線程并行執(zhí)行腳本的環(huán)境,可以處理一些異步任務(wù),如網(wǎng)絡(luò)請求、數(shù)據(jù)處理等,從而提高性能。
- 數(shù)據(jù)共享:Web Worker 可以通過消息傳遞機制與主線程通信,還可以共享數(shù)據(jù),這樣可以更高效地處理復(fù)雜的數(shù)據(jù)操作。
- 模塊化設(shè)計:將復(fù)雜的任務(wù)拆分成多個模塊,在不同的 Web Worker 中并行處理,可以提高代碼的可維護性和性能。
- 資源加載:Web Worker 無法訪問 DOM,因此在使用 Web Worker 時需要注意不能直接操作 DOM 元素,避免因此導(dǎo)致性能問題。
- 性能測試:在使用 Web Worker 優(yōu)化性能時,需要進行性能測試和監(jiān)控,以確保 Web Worker 的引入確實提高了頁面性能。
該文章在 2025/1/24 11:05:05 編輯過