JavaScript瀏覽器內(nèi)置的四大Web Worker的使用詳解
一、為什么 Web Worker 能實(shí)現(xiàn) “多線程”
瀏覽器的 JS 引擎(如 V8)本身是單線程的,但瀏覽器是多進(jìn)程 / 多線程架構(gòu)。Web Worker 的本質(zhì)是 瀏覽器為 JS 提供的 “額外線程池” ,核心原理:
- 線程隔離:Worker 線程與主線程是完全隔離的內(nèi)存空間(不共享堆內(nèi)存),通過(guò) “消息隊(duì)列” 通信(數(shù)據(jù)傳輸基于結(jié)構(gòu)化克隆算法,深拷貝)。
- 阻塞無(wú)關(guān)性:Worker 線程的阻塞(如死循環(huán))不會(huì)影響主線程,但會(huì)導(dǎo)致自身無(wú)法響應(yīng)消息。
- 資源限制:瀏覽器對(duì) Worker 數(shù)量有上限(通常同源下不超過(guò) 20 個(gè)),且單個(gè) Worker 占用的內(nèi)存有限制(避免濫用系統(tǒng)資源)。
關(guān)鍵區(qū)別:與 Node.js 的 child_process 不同,Web Worker 無(wú)法共享內(nèi)存(需通過(guò) SharedArrayBuffer 實(shí)現(xiàn)有限共享,見(jiàn)下文),且受瀏覽器安全策略(如跨域限制)約束。
總結(jié): webwork是通過(guò)js的方式喚起瀏覽器的內(nèi)置api使用,輔助前端計(jì)算的一種方式,就像fetch、ajaix那樣喚起瀏覽器的接口查詢一樣。
多線程四大API
Web Worker 是前端 “多線程” 的基礎(chǔ)規(guī)范,但瀏覽器針對(duì)不同場(chǎng)景設(shè)計(jì)了 4 種獨(dú)立的 Worker 類型—— 它們共享 “線程隔離” 的核心思想(避免阻塞主線程),但定位、能力、使用場(chǎng)景完全不同,均為 W3C 標(biāo)準(zhǔn)定義的原生 API(無(wú)需第三方庫(kù)),底層由瀏覽器獨(dú)立實(shí)現(xiàn)(無(wú)依賴關(guān)系)。
瀏覽器 4 種核心 Worker 類型對(duì)比表
| Worker 類型 | 核心定位 | 底層依賴 | 典型場(chǎng)景 |
|---|---|---|---|
| Web Worker | 主線程的 “計(jì)算助手”,處理耗時(shí)計(jì)算 | 瀏覽器線程池 | 大數(shù)據(jù)排序、加密解密、復(fù)雜算法計(jì)算 |
| Shared Worker | 多頁(yè)面共享的 “后臺(tái)協(xié)調(diào)者”,跨頁(yè)面通信 | 瀏覽器共享線程 | 多標(biāo)簽頁(yè)登錄狀態(tài)同步、跨頁(yè)數(shù)據(jù)協(xié)同 |
| Service Worker | 頁(yè)面離線的 “代理服務(wù)器”,攔截請(qǐng)求 + 緩存 | 瀏覽器后臺(tái)線程 | 離線應(yīng)用、請(qǐng)求攔截優(yōu)化、瀏覽器推送通知 |
| Worklet | 渲染管線的 “實(shí)時(shí)處理器”,介入渲染流程 | 瀏覽器渲染線程 | CSS 物理動(dòng)畫(huà)、音頻降噪、Canvas 渲染優(yōu)化 |
二、分類
1. Web Worker(計(jì)算型:解決主線程阻塞)
核心能力:
獨(dú)立于主線程的 “計(jì)算線程”,僅與創(chuàng)建它的主線程通信(一對(duì)一);
生命周期與頁(yè)面綁定(頁(yè)面關(guān)閉則 Worker 銷毀);
不阻塞 UI,專門處理耗時(shí)計(jì)算(避免頁(yè)面卡頓)。
示例:10 萬(wàn)條數(shù)據(jù)排序
// 主線程(main.js):發(fā)起計(jì)算請(qǐng)求,接收結(jié)果
if (window.Worker) {
// 1. 創(chuàng)建 Worker 實(shí)例
const sortWorker = new Worker('sort-worker.js');
// 2. 生成 10 萬(wàn)條隨機(jī)大數(shù)據(jù)(模擬復(fù)雜計(jì)算場(chǎng)景)
const bigData = Array.from({ length: 100000 }, () => Math.random() * 100000);
// 3. 發(fā)送數(shù)據(jù)給 Worker,觸發(fā)計(jì)算
sortWorker.postMessage(bigData);
console.log('主線程:已發(fā)送數(shù)據(jù),等待排序結(jié)果...');
// 4. 接收 Worker 返回的計(jì)算結(jié)果
sortWorker.onmessage = (e) => {
console.log('主線程:排序完成,前 10 條數(shù)據(jù):', e.data.slice(0, 10));
sortWorker.terminate(); // 計(jì)算完成,銷毀 Worker(避免內(nèi)存泄漏)
};
// 5. 監(jiān)聽(tīng) Worker 錯(cuò)誤(如代碼報(bào)錯(cuò))
sortWorker.onerror = (err) => {
console.error(`Worker 錯(cuò)誤:${err.message}(行號(hào):${err.lineno})`);
sortWorker.terminate();
};
} else {
console.error('當(dāng)前瀏覽器不支持 Web Worker');
}
// Worker 線程(sort-worker.js):執(zhí)行耗時(shí)計(jì)算
self.onmessage = (e) => {
const data = e.data;
console.log('Worker 線程:開(kāi)始排序 10 萬(wàn)條數(shù)據(jù)...');
// 耗時(shí)計(jì)算(示例用內(nèi)置排序,實(shí)際可替換為快排、歸并等復(fù)雜算法)
const sortedData = data.sort((a, b) => a - b);
// 向主線程返回結(jié)果
self.postMessage(sortedData);
self.close(); // Worker 主動(dòng)關(guān)閉,釋放資源
};
運(yùn)行效果:
主線程可正常處理用戶交互(點(diǎn)擊、滾動(dòng)),排序在后臺(tái)線程執(zhí)行,頁(yè)面無(wú)卡頓;計(jì)算完成后自動(dòng)銷毀 Worker,無(wú)內(nèi)存泄漏。
2. Shared Worker(協(xié)同型:多頁(yè)面數(shù)據(jù)同步)
核心能力:
同源多頁(yè)面可共享同一個(gè) Worker 實(shí)例(突破 “單頁(yè)面私有” 限制);
通過(guò) port(通信端口)實(shí)現(xiàn)多頁(yè)面與 Worker 的雙向通信;
適合跨頁(yè)面狀態(tài)同步(無(wú)需重復(fù)請(qǐng)求接口)。
示例:多標(biāo)簽頁(yè)登錄狀態(tài)同步
// 主線程 - 頁(yè)面 A(login.html):登錄后同步狀態(tài)
if (window.SharedWorker) {
// 1. 創(chuàng)建 Shared Worker 實(shí)例
const sharedWorker = new SharedWorker('sync-worker.js');
// 2. 激活通信端口(必須調(diào)用 start())
sharedWorker.port.start();
// 3. 模擬登錄按鈕點(diǎn)擊,發(fā)送登錄狀態(tài)給 Worker
document.getElementById('login-btn').addEventListener('click', () => {
const userInfo = { username: 'admin', isLogin: true };
sharedWorker.port.postMessage({ type: 'LOGIN', data: userInfo });
console.log('頁(yè)面 A:已發(fā)送登錄狀態(tài)');
});
// 4. 接收 Worker 廣播的消息(如其他頁(yè)面同步的狀態(tài))
sharedWorker.port.onmessage = (e) => {
console.log('頁(yè)面 A 收到消息:', e.data);
};
}
// 主線程 - 頁(yè)面 B(index.html):實(shí)時(shí)獲取登錄狀態(tài)
if (window.SharedWorker) {
const sharedWorker = new SharedWorker('sync-worker.js');
sharedWorker.port.start();
// 1. 向 Worker 請(qǐng)求當(dāng)前登錄狀態(tài)
sharedWorker.port.postMessage({ type: 'QUERY_STATUS' });
// 2. 接收狀態(tài)(頁(yè)面 A 登錄后,頁(yè)面 B 實(shí)時(shí)更新)
sharedWorker.port.onmessage = (e) => {
if (e.data.type === 'LOGIN_STATUS') {
document.getElementById('status').textContent = e.data.isLogin
? `已登錄:${e.data.username}`
: '未登錄';
}
};
}
// Shared Worker 線程(sync-worker.js):維護(hù)全局狀態(tài),廣播消息
const connections = []; // 存儲(chǔ)所有連接的頁(yè)面端口
let globalState = { isLogin: false, username: '' }; // 全局共享狀態(tài)
// 監(jiān)聽(tīng)頁(yè)面連接(新頁(yè)面打開(kāi)時(shí)觸發(fā))
self.onconnect = (e) => {
const port = e.ports[0];
connections.push(port); // 記錄新連接的頁(yè)面
port.start();
// 處理頁(yè)面發(fā)送的消息
port.onmessage = (msg) => {
switch (msg.data.type) {
case 'LOGIN':
// 更新全局狀態(tài)
globalState = msg.data.data;
// 廣播給所有連接的頁(yè)面(同步狀態(tài)到頁(yè)面 A、B...)
connections.forEach(p => p.postMessage({
type: 'LOGIN_STATUS',
...globalState
}));
break;
case 'QUERY_STATUS':
// 單獨(dú)響應(yīng)某個(gè)頁(yè)面的狀態(tài)查詢
port.postMessage({ type: 'LOGIN_STATUS', ...globalState });
break;
}
};
// 頁(yè)面關(guān)閉時(shí),移除端口(避免內(nèi)存泄漏)
port.onclose = () => {
const index = connections.indexOf(port);
if (index !== -1) connections.splice(index, 1);
};
};
運(yùn)行效果:
頁(yè)面 A 點(diǎn)擊 “登錄” 后,頁(yè)面 B 無(wú)需刷新,實(shí)時(shí)顯示 “已登錄:admin”;多標(biāo)簽頁(yè)共享同一登錄狀態(tài),無(wú)需重復(fù)調(diào)用登錄接口。
3. Service Worker(網(wǎng)絡(luò)型:離線緩存 + 請(qǐng)求攔截)
核心能力:
完全獨(dú)立于頁(yè)面,運(yùn)行在瀏覽器后臺(tái)(頁(yè)面關(guān)閉后仍可活動(dòng));
攔截所有網(wǎng)絡(luò)請(qǐng)求,可自定義緩存策略(實(shí)現(xiàn)離線訪問(wèn));
生命周期包含 “安裝→激活→運(yùn)行”,需手動(dòng)管理緩存版本。
示例:離線緩存靜態(tài)資源 + API 請(qǐng)求
// 主線程(main.js):注冊(cè) Service Worker,觸發(fā)離線邏輯
if ('serviceWorker' in navigator) {
window.addEventListener('load', async () => {
try {
// 1. 注冊(cè) Service Worker(腳本需在根目錄,確保作用域覆蓋所有頁(yè)面)
const registration = await navigator.serviceWorker.register('/sw.js');
console.log('Service Worker 注冊(cè)成功,作用域:', registration.scope);
// 2. 測(cè)試離線請(qǐng)求(首次聯(lián)網(wǎng)緩存,后續(xù)斷網(wǎng)可訪問(wèn))
fetch('/api/data').then(res => res.json()).then(data => {
console.log('API 請(qǐng)求結(jié)果:', data);
});
} catch (err) {
console.error('Service Worker 注冊(cè)失?。?, err);
}
});
}
// Service Worker 線程(sw.js):緩存+請(qǐng)求攔截邏輯
const CACHE_NAME = 'offline-cache-v1'; // 緩存版本(更新時(shí)修改版本號(hào))
// 需要緩存的資源列表(靜態(tài)資源+API接口)
const CACHE_ASSETS = [
'/',
'/index.html',
'/styles.css',
'/api/data' // 需緩存的 API 接口
];
// 1. 安裝階段:緩存靜態(tài)資源(僅首次注冊(cè)/版本更新時(shí)觸發(fā))
self.addEventListener('install', (event) => {
// 等待緩存完成后,再進(jìn)入激活階段
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(CACHE_ASSETS)) // 批量緩存資源
.then(() => self.skipWaiting()) // 跳過(guò)等待,立即激活新 Worker(替換舊版本)
);
});
// 2. 激活階段:清理舊緩存(避免緩存膨脹)
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then(cacheNames => {
// 刪除非當(dāng)前版本的緩存
return Promise.all(
cacheNames.filter(name => name !== CACHE_NAME).map(name => caches.delete(name))
);
}).then(() => self.clients.claim()) // 強(qiáng)制所有打開(kāi)的頁(yè)面使用新 Worker
);
});
// 3. 攔截請(qǐng)求:優(yōu)先從緩存返回,無(wú)緩存則請(qǐng)求網(wǎng)絡(luò)
self.addEventListener('fetch', (event) => {
// 僅攔截同源的 GET 請(qǐng)求(避免跨域資源和非冪等請(qǐng)求)
if (event.request.method === 'GET' && event.request.mode === 'same-origin') {
event.respondWith(
caches.match(event.request)
.then(cachedResponse => {
// 緩存命中:直接返回緩存資源
if (cachedResponse) {
console.log('從緩存返回:', event.request.url);
return cachedResponse;
}
// 緩存未命中:發(fā)起網(wǎng)絡(luò)請(qǐng)求,并緩存新結(jié)果
return fetch(event.request).then(networkResponse => {
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, networkResponse.clone()); // 緩存新請(qǐng)求
});
return networkResponse;
});
})
);
}
});
運(yùn)行效果:
首次聯(lián)網(wǎng)時(shí),自動(dòng)緩存 index.html、styles.css 和 /api/data;
斷網(wǎng)后刷新頁(yè)面,仍能正常加載頁(yè)面和 API 數(shù)據(jù)(從緩存讀?。?;
緩存版本更新時(shí),自動(dòng)清理舊緩存,避免資源冗余。
4. Worklet(實(shí)時(shí)型:介入渲染流程)
核心能力:
嵌入瀏覽器渲染管線(如 CSS 引擎線程、音頻線程),低延遲(<1ms);
直接干預(yù)渲染過(guò)程(動(dòng)畫(huà)、繪制、音頻處理),彌補(bǔ) Web Worker 通信延遲的缺陷;
細(xì)分類型:CSSWorklet(動(dòng)畫(huà))、AudioWorklet(音頻)、PaintWorklet(繪制)。
示例:CSSWorklet 實(shí)現(xiàn)物理彈性動(dòng)畫(huà)
// 主線程(main.js):注冊(cè) Worklet,關(guān)聯(lián)動(dòng)畫(huà)
if ('CSSWorklet' in window) {
try {
// 注冊(cè)自定義 Worklet(加載動(dòng)畫(huà)邏輯腳本)
await CSSWorklet.addModule('bounce-worklet.js');
console.log('CSSWorklet 注冊(cè)成功');
} catch (err) {
console.error('CSSWorklet 注冊(cè)失敗:', err);
}
}
// HTML 結(jié)構(gòu):動(dòng)畫(huà)元素
/*
<div class="box">彈性動(dòng)畫(huà)方塊</div>
*/
// CSS 樣式:綁定 Worklet 動(dòng)畫(huà)
/*
.box {
width: 100px;
height: 100px;
background: red;
/* 使用 Worklet 定義的動(dòng)畫(huà)(名稱與 Worklet 中注冊(cè)一致) */
animation: bounce 2s infinite;
}
/* 定義動(dòng)畫(huà)進(jìn)度(from→to 對(duì)應(yīng) Worklet 中的 0→1) */
@keyframes bounce {
from { transform: translateY(0); }
to { transform: translateY(300px); }
}
*/
// CSSWorklet 線程(bounce-worklet.js):自定義動(dòng)畫(huà)邏輯
class BounceWorklet {
// 每一幀的計(jì)算(嵌入渲染管線,實(shí)時(shí)執(zhí)行)
process(inputs, outputs, parameters) {
const [t] = inputs; // 動(dòng)畫(huà)進(jìn)度(0~1,from→to)
const [output] = outputs; // 輸出結(jié)果(最終的 CSS 樣式值)
// 物理彈性公式(模擬重力+反彈效果,非勻速動(dòng)畫(huà))
const bounce = Math.sin(t * Math.PI) * Math.exp(-t * 0.5);
// 輸出 transform 樣式(控制方塊位置)
output.value = `translateY(${300 * (1 - bounce)}px)`;
}
}
// 注冊(cè) Worklet 動(dòng)畫(huà)(名稱需與 CSS 中的 @keyframes 名稱一致)
registerAnimator('bounce', BounceWorklet);
運(yùn)行效果:
紅色方塊以 “物理彈性軌跡” 上下運(yùn)動(dòng)(類似小球落地反彈),動(dòng)畫(huà)流暢無(wú)卡頓;Worklet 運(yùn)行在渲染線程,延遲極低,避免 Web Worker 通信導(dǎo)致的動(dòng)畫(huà)掉幀。
三、混合使用:多 Worker 協(xié)同解決復(fù)雜場(chǎng)景
場(chǎng)景需求:離線數(shù)據(jù)分析 Dashboard
需要同時(shí)滿足 4 個(gè)核心需求:
離線訪問(wèn)(斷網(wǎng)后仍可查看歷史數(shù)據(jù));
多標(biāo)簽頁(yè)同步分析結(jié)果(無(wú)需重復(fù)解析);
后臺(tái)解析 10 萬(wàn)條 CSV 數(shù)據(jù)(不阻塞頁(yè)面);
實(shí)時(shí)渲染流暢圖表(動(dòng)畫(huà)無(wú)掉幀)。
完整實(shí)現(xiàn)代碼(整合 4 種 Worker)
// 主線程(dashboard.js):整合所有 Worker,協(xié)調(diào)流程
if ('serviceWorker' in navigator) {
window.addEventListener('load', async () => {
try {
// 1. 第一步:注冊(cè) Service Worker(離線緩存)
const swRegistration = await navigator.serviceWorker.register('/sw.js');
console.log('Service Worker 注冊(cè)成功');
// 2. 第二步:創(chuàng)建 Shared Worker(多頁(yè)面同步)
const sharedWorker = new SharedWorker('sync-worker.js');
sharedWorker.port.start();
// 3. 第三步:創(chuàng)建 Web Worker(CSV 數(shù)據(jù)解析)
const csvWorker = new Worker('csv-worker.js');
// 4. 第四步:注冊(cè) CSSWorklet(圖表動(dòng)畫(huà)優(yōu)化)
if ('CSSWorklet' in window) {
await CSSWorklet.addModule('chart-worklet.js');
console.log('CSSWorklet 注冊(cè)成功');
}
// 5. 頁(yè)面元素:文件上傳、圖表容器、狀態(tài)文本
const fileInput = document.getElementById('file-upload');
const chartContainer = document.getElementById('chart-container');
const statusText = document.getElementById('status');
// 6. 監(jiān)聽(tīng)文件上傳:觸發(fā) CSV 解析
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file && file.name.endsWith('.csv')) {
statusText.textContent = '正在解析 CSV 文件...';
csvWorker.postMessage(file); // 發(fā)送文件給 Web Worker
} else {
statusText.textContent = '請(qǐng)上傳 CSV 格式文件!';
}
});
// 7. 接收 Web Worker 解析結(jié)果:渲染+同步+緩存
csvWorker.onmessage = (e) => {
const analysisResult = e.data; // 解析結(jié)果(數(shù)據(jù)數(shù)組+統(tǒng)計(jì)信息)
// 7.1 渲染圖表(用 CSSWorklet 優(yōu)化動(dòng)畫(huà))
renderChart(analysisResult, chartContainer);
// 7.2 同步結(jié)果到其他標(biāo)簽頁(yè)(通過(guò) Shared Worker)
sharedWorker.port.postMessage({
type: 'ANALYSIS_RESULT',
data: analysisResult
});
// 7.3 緩存結(jié)果到 Service Worker(支持離線訪問(wèn))
if (navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage({
type: 'CACHE_RESULT',
key: 'last-csv-analysis',
data: analysisResult
});
}
// 7.4 更新?tīng)顟B(tài)文本
statusText.textContent = `解析完成:共 ${analysisResult.totalCount} 條</doubaocanvas>
四、關(guān)于self
1. 來(lái)源:Worker 線程的內(nèi)置全局對(duì)象,瀏覽器自動(dòng)注入,無(wú)需定義
2. 作用:等同于主線程的 window,是 Worker 線程訪問(wèn)自身能力的入口
3. 隔離性:不同 Worker 的 self 是獨(dú)立實(shí)例,互不干擾(如 Web Worker 的 self ≠ Service Worker 的 self)
4. 核心能力:接收/發(fā)送消息(onmessage/postMessage)、管理生命周期(close)、調(diào)用 Worker 專屬 API
Worker 中 self 的簡(jiǎn)單代碼示例
// Worker 線程(calc-worker.js)
// self 指向當(dāng)前 Web Worker 實(shí)例,僅用于計(jì)算相關(guān)邏輯
self.onmessage = (e) => {
const { num1, num2 } = e.data;
const sum = num1 + num2; // 簡(jiǎn)單計(jì)算:兩數(shù)相加
self.postMessage(sum); // 用 self 向主線程返回結(jié)果
self.close(); // 用 self 主動(dòng)關(guān)閉 Worker,釋放資源
};
// 主線程(main.js)- 配合使用
const calcWorker = new Worker('calc-worker.js');
calcWorker.postMessage({ num1: 10, num2: 20 }); // 發(fā)數(shù)據(jù)給 Worker
calcWorker.onmessage = (e) => {
console.log('計(jì)算結(jié)果:', e.data); // 輸出 30
};
注意
Worker 中不能用 window,必須用 self(因 Worker 無(wú)窗口概念)
self 無(wú)法訪問(wèn) DOM(如 document、body),僅能處理非 UI 邏輯
簡(jiǎn)單場(chǎng)景可省略 self(如 onmessage = () => {} 等同于 self.onmessage = () => {}),但復(fù)雜場(chǎng)景建議保留,增強(qiáng)可讀性
五、生產(chǎn)環(huán)境使用的平衡點(diǎn)
1. 錯(cuò)誤處理與健壯性
Worker 內(nèi)部錯(cuò)誤不會(huì)冒泡到主線程,需單獨(dú)監(jiān)聽(tīng):
// 主線程
worker.onerror = (err) => {
console.error(`Worker錯(cuò)誤:${err.message}`);
worker.terminate(); // 出錯(cuò)后銷毀Worker,避免內(nèi)存泄漏
};
// Worker線程
self.onerror = (err) => {
self.postMessage({ type: 'ERROR', message: err.message });
self.close(); // 主動(dòng)關(guān)閉
};
網(wǎng)絡(luò)錯(cuò)誤:Worker 腳本加載失敗(404)時(shí),主線程會(huì)觸發(fā) error 事件,需捕獲并降級(jí)處理。
2. 內(nèi)存管理與資源回收
- 避免創(chuàng)建過(guò)多 Worker:每個(gè) Worker 都是獨(dú)立線程,占用內(nèi)存和 CPU,建議通過(guò) “Worker 池” 復(fù)用(如用
p-queue管理 Worker 實(shí)例)。 - 及時(shí)銷毀無(wú)用 Worker:
worker.terminate()(主線程主動(dòng)銷毀,立即終止)或self.close()(Worker 主動(dòng)關(guān)閉,清理后終止)。 - 警惕內(nèi)存泄漏:Worker 中若持有
setInterval、未關(guān)閉的fetch請(qǐng)求等,即使調(diào)用terminate也可能導(dǎo)致內(nèi)存泄漏,需先清理資源。
3. 跨域與安全策略
- Worker 腳本必須與主線程同源(協(xié)議、域名、端口一致),若需加載跨域腳本,需通過(guò)
importScripts加載且服務(wù)器允許跨域(Access-Control-Allow-Origin)。 - 禁止訪問(wèn)
file://協(xié)議下的腳本(瀏覽器安全限制),本地開(kāi)發(fā)需用http-server啟動(dòng)服務(wù)。 - 敏感操作限制:Worker 中無(wú)法使用
localStorage(部分瀏覽器支持,但規(guī)范不推薦),建議用IndexedDB存儲(chǔ)大量數(shù)據(jù)(異步 API,不阻塞)。
4. 兼容性處理與降級(jí)方案
瀏覽器支持:IE 完全不支持,Edge 12+、Chrome 4+、Firefox 3.5+ 支持基本特性,SharedArrayBuffer 和 SharedWorker 兼容性較差。
降級(jí)邏輯:
if (window.Worker) {
// 使用Worker
} else {
// 降級(jí)到主線程執(zhí)行(給用戶提示“當(dāng)前瀏覽器可能卡頓”)
heavyTask();
}
六、性能陷阱
過(guò)度使用 Worker 導(dǎo)致性能反降小數(shù)據(jù)計(jì)算(如幾毫秒可完成的操作)用 Worker 反而會(huì)增加通信開(kāi)銷(序列化 + 消息傳遞),建議僅對(duì) 執(zhí)行時(shí)間 > 50ms 的任務(wù)使用 Worker。
頻繁通信導(dǎo)致主線程阻塞若 Worker 與主線程高頻次 postMessage(如每秒 hundreds 次),序列化數(shù)據(jù)會(huì)占用主線程資源,導(dǎo)致卡頓。解決方案:
- 批量發(fā)送數(shù)據(jù)(累計(jì)一定量后再通信);
- 用
SharedArrayBuffer減少序列化開(kāi)銷。
Worker 中濫用同步 APIWorker 雖然不阻塞 UI,但內(nèi)部的同步操作(如 XMLHttpRequest 的同步請(qǐng)求、大量同步循環(huán))會(huì)阻塞自身線程,導(dǎo)致無(wú)法響應(yīng)消息。建議優(yōu)先使用異步 API(fetch、setImmediate)。
忽略線程優(yōu)先級(jí)瀏覽器會(huì)給 Worker 分配較低的線程優(yōu)先級(jí),若需 “近實(shí)時(shí)” 處理(如游戲幀計(jì)算),可能出現(xiàn)延遲。此時(shí)可考慮 requestIdleCallback 結(jié)合 Worker,利用主線程空閑時(shí)間處理。
到此這篇關(guān)于JavaScript瀏覽器內(nèi)置的四大Web Worker的使用詳解的文章就介紹到這了,更多相關(guān)JavaScript多線程Web Worker內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
BootStrap 智能表單實(shí)戰(zhàn)系列(十)自動(dòng)完成組件的支持
這篇文章主要介紹了BootStrap 智能表單實(shí)戰(zhàn)系列(十)自動(dòng)完成組件的支持 的相關(guān)資料,需要的朋友可以參考下2016-06-06
js實(shí)現(xiàn)iframe自動(dòng)自適應(yīng)高度的方法
這篇文章主要介紹了js實(shí)現(xiàn)iframe自動(dòng)自適應(yīng)高度的方法,涉及javascript操作iframe框架的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02
JavaScript 瀏覽器對(duì)象模型BOM原理與常見(jiàn)用法實(shí)例分析
這篇文章主要介紹了JavaScript 瀏覽器對(duì)象模型BOM原理與常見(jiàn)用法,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript瀏覽器對(duì)象模型BOM基本概念、原理、使用方法及操作注意事項(xiàng),需要的朋友可以參考下2019-12-12
js實(shí)現(xiàn)電梯導(dǎo)航效果的示例代碼
這篇文章主要介紹了JavaScript實(shí)現(xiàn)電梯導(dǎo)航效果的相關(guān)知識(shí),文中通過(guò)示例代碼介紹的很詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-12-12
JavaScript數(shù)據(jù)類型及相互間的轉(zhuǎn)換規(guī)則
這篇文章主要介紹了JavaScript數(shù)據(jù)類型及相互間的轉(zhuǎn)換規(guī)則,文章通過(guò)圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
js中將具有數(shù)字屬性名的對(duì)象轉(zhuǎn)換為數(shù)組
js中將具有數(shù)字屬性名的對(duì)象轉(zhuǎn)換為數(shù)組,雖然不太常用,但我們的確可以給對(duì)象添加以數(shù)字為屬性名的屬性2011-03-03
Fullpage.js固定導(dǎo)航欄-實(shí)現(xiàn)定位導(dǎo)航欄
FullPage.js 是一個(gè)簡(jiǎn)單而易于使用的插件,用來(lái)創(chuàng)建全屏滾動(dòng)網(wǎng)站(也被稱為單頁(yè)網(wǎng)站)。接下來(lái)通過(guò)本文給大家介紹Fullpage.js固定導(dǎo)航欄-實(shí)現(xiàn)定位導(dǎo)航欄,對(duì)fullpage.js導(dǎo)航欄相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-03-03

