Web Worker
是什么
Web Workers 是浏览器提供的 JavaScript API,允许在后台线程中运行脚本,从而避免阻塞主线程(UI 线程),提高 Web 应用的响应性能和用户体验。
核心特性
- 多线程能力:在独立线程中执行耗时任务(如计算、数据处理),不影响页面交互。
- 通信方式:通过
postMessage()和onmessage事件与主线程通信,数据为值传递(结构化克隆算法)或可转移对象(如 ArrayBuffer)。
本文介绍 Web Worker API,允许在后台线程运行脚本以避免阻塞主线程。涵盖专用、共享、Service Worker 等类型及基本用法。详细列举了大数据处理、图像滤镜、实时数据流、文件解析、机器学习推理等实际应用场景,并提供了分片处理、可转移对象优化及 Worker 池管理等性能提升技巧。旨在帮助开发者利用多线程能力提升 Web 应用性能。
Web Workers 是浏览器提供的 JavaScript API,允许在后台线程中运行脚本,从而避免阻塞主线程(UI 线程),提高 Web 应用的响应性能和用户体验。
postMessage() 和 onmessage 事件与主线程通信,数据为值传递(结构化克隆算法)或可转移对象(如 ArrayBuffer)。new Worker('worker.js')。// 创建 Worker
const worker = new Worker('worker.js');
// 向 Worker 发送数据
worker.postMessage('Hello from main thread!');
// 接收 Worker 返回的数据
worker.onmessage = (event) => {
console.log('From worker:', event.data);
};
// 错误处理
worker.onerror = (error) => {
console.error('Worker error:', error);
};
// 监听主线程消息
self.onmessage = (event) => {
console.log('From main:', event.data);
// 执行耗时任务
const result = heavyCalculation();
// 返回结果
self.postMessage(result);
};
function heavyCalculation() {
// 模拟复杂计算
return Array.from({ length: 1000 }, (_, i) => i * 2);
}
self 或 this 代替 window。new Worker('worker.js', { type: 'module' }) 使用 ES6 模块。// 主线程中终止
worker.terminate();
// Worker 内部自终止
self.close();
通过合理使用 Web Workers,可以显著提升复杂 Web 应用的性能表现,尤其是在大量计算或高频率任务处理场景中。
// 处理大型数据集(10 万 + 行数据)
// worker.js
self.onmessage = function(e) {
const data = e.data;
const results = [];
// 复杂数据转换
data.forEach(item => {
const processed = {
...item,
score: calculateScore(item),
trend: analyzeTrend(item.history)
};
results.push(processed);
});
// 分批返回结果,避免内存压力
for (let i = 0; i < results.length; i += 1000) {
self.postMessage({
type: 'progress',
data: results.slice(i, i + 1000),
progress: ((i / results.length * 100).toFixed(1))
});
}
self.postMessage({ type: 'complete' });
};
// 实时图片滤镜应用
// image-worker.js
self.onmessage = async function(e) {
const { imageData, filterType, width, height } = e.data;
switch (filterType) {
case 'grayscale':
applyGrayscale(imageData.data);
break;
case 'blur':
applyGaussianBlur(imageData.data, width, height);
break;
case 'edgeDetection':
applySobelOperator(imageData.data, width, height);
break;
}
self.postMessage({ imageData });
};
function applyGrayscale(pixels) {
for (let i = 0; i < pixels.length; i += 4) {
const avg = (pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3;
pixels[i] = pixels[i + 1] = pixels[i + 2] = avg;
}
}
// 处理 WebSocket 实时数据流
// stream-worker.js
let websocket = null;
let buffer = [];
self.onmessage = function(e) {
const { type, data } = e.data;
if (type === 'connect') {
// 在 Worker 中建立 WebSocket 连接
websocket = new WebSocket(data.url);
websocket.onmessage = handleWebSocketMessage;
} else if (type === 'process') {
// 处理接收的数据
const processed = data.map(processTradeData);
buffer.push(...processed);
// 批量处理,每 100 条发送一次
if (buffer.length >= 100) {
self.postMessage({ trades: buffer.slice(0, 100) });
buffer = buffer.slice(100);
}
}
};
// 解析大型 Excel 文件
// excel-worker.js
importScripts('https://unpkg.com/xlsx/dist/xlsx.full.min.js');
self.onmessage = function(e) {
const { file, options } = e.data;
const reader = new FileReader();
reader.onload = function(event) {
const data = new Uint8Array(event.target.result);
const workbook = XLSX.read(data, { type: 'array' });
// 分片处理每个 sheet
workbook.SheetNames.forEach(sheetName => {
const worksheet = workbook.Sheets[sheetName];
const jsonData = XLSX.utils.sheet_to_json(worksheet, { raw: false, defval: '' });
// 分批发送回主线程
const chunkSize = 1000;
for (let i = 0; i < jsonData.length; i += chunkSize) {
const chunk = jsonData.slice(i, i + chunkSize);
self.postMessage({
type: 'chunk',
sheet: sheetName,
data: chunk,
progress: (i / jsonData.length * 100)
});
}
});
self.postMessage({ type: 'complete' });
};
reader.readAsArrayBuffer(file);
};
// 机器学习推理(使用 TensorFlow.js)
// ml-worker.js
importScripts('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest');
let model = null;
self.onmessage = async function(e) {
const { action, data } = e.data;
if (action === 'loadModel') {
// 加载模型
model = await tf.loadLayersModel(data.modelUrl);
self.postMessage({ status: 'model_loaded' });
} else if (action === 'predict') {
// 批量预测
const inputs = tf.tensor(data);
const predictions = model.predict(inputs);
const results = await predictions.array();
// 清理内存
inputs.dispose();
predictions.dispose();
self.postMessage({ predictions: results });
} else if (action === 'train') {
// 在后台训练模型
await trainModel(data);
self.postMessage({ status: 'training_complete' });
}
};
// 音频频谱分析
// audio-worker.js
let audioContext = null;
let analyser = null;
let dataArray = null;
self.onmessage = function(e) {
const { type, audioBuffer, sampleRate } = e.data;
if (type === 'init') {
audioContext = new (self.AudioContext || self.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 2048;
dataArray = new Uint8Array(analyser.frequencyBinCount);
} else if (type === 'analyze') {
// 实时分析音频
const source = audioContext.createBufferSource();
source.buffer = audioBuffer;
source.connect(analyser);
source.start();
// 定期获取频谱数据
const interval = setInterval(() => {
analyser.getByteFrequencyData(dataArray);
self.postMessage({
frequencies: Array.from(dataArray),
timestamp: Date.now()
});
}, 50);
source.onended = () => {
clearInterval(interval);
self.postMessage({ status: 'ended' });
};
}
};
// 游戏物理计算
// physics-worker.js
class PhysicsWorld {
constructor() {
this.objects = [];
this.gravity = 9.8;
}
update(deltaTime) {
// 并行更新所有物体
for (const obj of this.objects) {
this.applyPhysics(obj, deltaTime);
}
// 碰撞检测
this.checkCollisions();
return this.objects.map(obj => ({
id: obj.id,
position: obj.position,
velocity: obj.velocity
}));
}
applyPhysics(obj, deltaTime) {
// 计算物理效果
obj.velocity.y -= this.gravity * deltaTime;
obj.position.x += obj.velocity.x * deltaTime;
obj.position.y += obj.velocity.y * deltaTime;
// 边界检测
if (obj.position.y < 0) {
obj.position.y = 0;
obj.velocity.y *= -0.8; // 弹性
}
}
}
let world = new PhysicsWorld();
self.onmessage = function(e) {
const { action, data, deltaTime } = e.data;
if (action === 'update') {
const updates = world.update(deltaTime);
self.postMessage({ type: 'physics_update', data: updates });
}
};
// 处理 GeoJSON 地图数据
// map-worker.js
self.onmessage = function(e) {
const { geojson, bounds, zoom } = e.data;
// 筛选视口内的要素
const visibleFeatures = geojson.features.filter(feature => {
return isInBounds(feature.geometry, bounds);
});
// 生成简化几何体(根据缩放级别)
const simplified = simplifyGeometry(visibleFeatures, zoom);
// 生成空间索引
const spatialIndex = createRTree(simplified);
self.postMessage({ features: simplified, spatialIndex, bounds });
};
// 批量图片压缩
// compress-worker.js
importScripts('https://cdn.jsdelivr.net/npm/jimp@latest/browser/lib/jimp.min.js');
self.onmessage = async function(e) {
const { images, quality, maxWidth } = e.data;
const results = [];
for (let i = 0; i < images.length; i++) {
const image = images[i];
// 使用 JIMP 库处理图片
const jimpImage = await self.Jimp.read(image.data);
if (maxWidth) {
jimpImage.resize(maxWidth, self.Jimp.AUTO);
}
jimpImage.quality(quality);
// 转换为 Blob
const buffer = await jimpImage.getBufferAsync(self.Jimp.MIME_JPEG);
const compressed = new Blob([buffer], { type: 'image/jpeg' });
results.push({
name: image.name,
originalSize: image.size,
compressedSize: compressed.size,
data: compressed
});
// 进度更新
self.postMessage({
type: 'progress',
current: i + 1,
total: images.length
});
}
self.postMessage({ type: 'complete', results });
};
// 处理实时监控数据
// monitoring-worker.js
class DataAggregator {
constructor() {
this.metrics = new Map();
this.windowSize = 60000; // 1 分钟窗口
}
addMetric(metric) {
const now = Date.now();
const key = metric.name;
if (!this.metrics.has(key)) {
this.metrics.set(key, []);
}
const values = this.metrics.get(key);
values.push({ timestamp: now, value: metric.value });
// 清理旧数据
const cutoff = now - this.windowSize;
this.metrics.set(key, values.filter(v => v.timestamp > cutoff));
}
getAggregates() {
const aggregates = {};
for (const [key, values] of this.metrics) {
if (values.length === 0) continue;
const nums = values.map(v => v.value);
aggregates[key] = {
avg: nums.reduce((a, b) => a + b) / nums.length,
min: Math.min(...nums),
max: Math.max(...nums),
latest: values[values.length - 1].value,
count: nums.length
};
}
return aggregates;
}
}
const aggregator = new DataAggregator();
// 定时生成聚合数据
setInterval(() => {
const aggregates = aggregator.getAggregates();
self.postMessage({
type: 'aggregates',
data: aggregates,
timestamp: Date.now()
});
}, 1000);
self.onmessage = function(e) {
if (e.data.type === 'metric') {
aggregator.addMetric(e.data.metric);
}
};
// 分片处理大数据
function processInChunks(data, chunkSize, processFn) {
for (let i = 0; i < data.length; i += chunkSize) {
const chunk = data.slice(i, i + chunkSize);
const result = processFn(chunk);
// 允许主线程处理 UI
if (i % (chunkSize * 10) === 0) {
setTimeout(() => {}, 0);
}
self.postMessage({ chunk: result, index: i });
}
}
// 使用可转移对象避免复制
const largeBuffer = new ArrayBuffer(1024 * 1024 * 100); // 100MB
const view = new Uint8Array(largeBuffer);
// 填充数据
for (let i = 0; i < view.length; i++) {
view[i] = i % 256;
}
// 转移所有权而不是复制
self.postMessage({ buffer: largeBuffer }, [largeBuffer]);
class WorkerPool {
constructor(workerScript, poolSize = 4) {
this.workers = [];
this.queue = [];
for (let i = 0; i < poolSize; i++) {
const worker = new Worker(workerScript);
worker.onmessage = this.handleResult.bind(this, worker);
this.workers.push({ worker, busy: false });
}
}
execute(task) {
const available = this.workers.find(w => !w.busy);
if (available) {
available.busy = true;
available.worker.postMessage(task);
} else {
this.queue.push(task);
}
}
}
这些实际应用展示了 Web Worker 在各种场景下的强大能力,特别是处理 CPU 密集型任务时,能显著提升 Web 应用性能。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online