全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-16 8 分钟 ✍️ juanwangdev

JavaScript Web Workers 与多线程

JavaScript 默认单线程执行,Web Workers 提供真正的多线程能力,在后台线程执行脚本,不阻塞主线程 UI。

Worker 基本用法

JavaScript
// 主线程:创建 Worker
const worker = new Worker('worker.js');

// 发送消息
worker.postMessage({ type: 'compute', data: [1, 2, 3, 4, 5] });

// 接收消息
worker.onmessage = (event) => {
    console.log('Worker 结果:', event.data);
};

// 错误处理
worker.onerror = (error) => {
    console.error('Worker 错误:', error.message);
};

// 终止 Worker
worker.terminate();
JavaScript
// worker.js:Worker 线程代码
// 监听主线程消息
self.onmessage = (event) => {
    const { type, data } = event.data;

    if (type === 'compute') {
        // 执行计算
        const result = data.reduce((sum, n) => sum + n * n, 0);

        // 发送结果回主线程
        self.postMessage({ type: 'result', data: result });
    }
};

// Worker 内错误处理
self.onerror = (error) => {
    console.error('Worker 错误:', error);
};

内联 Worker

JavaScript
// Blob URL 创建内联 Worker(无需单独文件)
const workerCode = `
    self.onmessage = (e) => {
        const result = e.data.map(x => x * x);
        self.postMessage(result);
    };
`;

const blob = new Blob([workerCode], { type: 'application/javascript' });
const workerUrl = URL.createObjectURL(blob);
const worker = new Worker(workerUrl);

worker.postMessage([1, 2, 3, 4]);
worker.onmessage = (e) => console.log(e.data);  // [1, 4, 9, 16]

// 清理 Blob URL
URL.revokeObjectURL(workerUrl);
worker.terminate();

数据传输方式

JavaScript
// 结构化克隆:默认方式,复制数据
const data = new Uint8Array([1, 2, 3, 4, 5]);
worker.postMessage(data);  // 数据被复制,主线程仍可访问
console.log(data);  // [1, 2, 3, 4, 5]

// Transferable 对象:转移所有权,零拷贝
const largeData = new Uint8Array(10000000);
worker.postMessage(largeData, [largeData.buffer]);  // 转移 buffer
console.log(largeData.length);  // 0(主线程不再拥有)

// worker.js
self.onmessage = (e) => {
    const data = e.data;
    // 直接使用转移的数据
    console.log('收到数据:', data.length);
};

SharedArrayBuffer 共享内存

JavaScript
// 主线程:创建共享内存
const sharedBuffer = new SharedArrayBuffer(1024);
const sharedArray = new Uint8Array(sharedBuffer);

// 初始化数据
for (let i = 0; i < sharedArray.length; i++) {
    sharedArray[i] = i;
}

// 发送到多个 Worker(共享同一内存)
const workers = [];
for (let i = 0; i < 4; i++) {
    const worker = new Worker('shared-worker.js');
    worker.postMessage({ buffer: sharedBuffer, workerId: i });
    workers.push(worker);
}

// worker.js:操作共享内存
self.onmessage = (e) => {
    const { buffer, workerId } = e.data;
    const array = new Uint8Array(buffer);

    // 原子操作确保安全
    Atomics.add(array, workerId, 10);

    self.postMessage({ workerId, done: true });
};

Worker 类型

JavaScript
// Dedicated Worker:专用 Worker,一对一通信
const dedicated = new Worker('worker.js');

// Shared Worker:共享 Worker,多页面共享
const shared = new SharedWorker('shared-worker.js');
shared.port.onmessage = (e) => console.log(e.data);
shared.port.postMessage('hello');

// Service Worker:缓存和离线支持
// 注册 Service Worker
navigator.serviceWorker.register('/sw.js').then(reg => {
    console.log('Service Worker 注册成功');
});

// sw.js
self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open('v1').then(cache => cache.addAll(['/index.html', '/app.js']))
    );
});

self.addEventListener('fetch', (event) => {
    event.respondWith(
        caches.match(event.request).then(response => response || fetch(event.request))
    );
});

Worker 通信模式

JavaScript
// 单向消息
worker.postMessage('单向消息');

// 双向请求-响应
function workerRequest(worker, data) {
    return new Promise((resolve) => {
        const handler = (e) => {
            if (e.data.id === data.id) {
                worker.removeEventListener('message', handler);
                resolve(e.data.result);
            }
        };
        worker.addEventListener('message', handler);
        worker.postMessage(data);
    });
}

// 使用
const result = await workerRequest(worker, { id: 1, task: 'compute' });

// BroadcastChannel:跨 Worker 通信
const channel = new BroadcastChannel('worker-channel');
channel.postMessage({ from: 'main', data: 'hello' });
channel.onmessage = (e) => console.log('收到:', e.data);

// Worker 内也可以创建 BroadcastChannel
// worker.js
const channel = new BroadcastChannel('worker-channel');
channel.onmessage = (e) => {
    console.log('Worker 收到:', e.data);
    channel.postMessage({ from: 'worker', reply: '收到' });
};

计算密集型任务示例

JavaScript
// 主线程:大数据计算委托给 Worker
function parallelCompute(data, workerCount = 4) {
    const chunkSize = Math.ceil(data.length / workerCount);
    const workers = [];
    const results = [];

    return new Promise((resolve) => {
        for (let i = 0; i < workerCount; i++) {
            const worker = new Worker('compute-worker.js');
            const chunk = data.slice(i * chunkSize, (i + 1) * chunkSize);

            worker.postMessage({ chunk, index: i });

            worker.onmessage = (e) => {
                results[e.data.index] = e.data.result;

                if (results.length === workerCount && results.every(r => r !== undefined)) {
                    workers.forEach(w => w.terminate());
                    resolve(results.flat());
                }
            };

            workers.push(worker);
        }
    });
}

// 使用
const largeArray = Array.from({ length: 100000 }, (_, i) => i);
const result = await parallelCompute(largeArray);
JavaScript
// compute-worker.js
self.onmessage = (e) => {
    const { chunk, index } = e.data;

    // 执行计算
    const result = chunk.map(x => x * x * x);

    self.postMessage({ result, index });
};

Worker 线程限制

JavaScript
// Worker 内可用:
// - XMLHttpRequest / fetch
// - WebSocket
// - IndexedDB
// - setTimeout / setInterval
// - Atomics / SharedArrayBuffer
// - 其他 Worker(嵌套 Worker)

// Worker 内不可用:
// - DOM 操作(document, window)
// - parent 对象
// - location(可读但不可写)
// - localStorage / sessionStorage(可用 IndexedDB 替代)
// - alert / confirm / prompt
// - UI 相关 API

// Worker 内创建嵌套 Worker
const subWorker = new Worker('sub-worker.js');
subWorker.postMessage('from main worker');

注意事项

  • Worker 有启动开销,适合长时间任务,短任务不值得
  • 数据传输默认复制,大数据用 Transferable 零拷贝
  • Worker 与主线程完全隔离,无 DOM 访问
  • 创建过多 Worker 消耗资源,建议池化管理
JavaScript
// Worker 池
class WorkerPool {
    constructor(workerScript, poolSize = 4) {
        this.workers = Array.from({ length: poolSize }, () => new Worker(workerScript));
        this.busy = new Set();
    }

    async execute(data) {
        const available = this.workers.find(w => !this.busy.has(w));
        if (!available) {
            // 等待可用 Worker
            return new Promise(resolve => {
                this.queue.push({ data, resolve });
            });
        }

        this.busy.add(available);
        return new Promise(resolve => {
            available.onmessage = (e) => {
                this.busy.delete(available);
                resolve(e.data);

                if (this.queue.length) {
                    const next = this.queue.shift();
                    this.execute(next.data).then(next.resolve);
                }
            };
            available.postMessage(data);
        });
    }

    terminate() {
        this.workers.forEach(w => w.terminate());
    }
}

要点总结

  • Web Workers 在独立线程执行,不阻塞主线程 UI
  • postMessage 通信,onmessage 接收,terminate 终止
  • 数据传输默认复制,Transferable 实现零拷贝转移
  • SharedArrayBuffer + Atomics 实现线程安全共享内存
  • Worker 无 DOM 访问,可用 fetch、IndexedDB、WebSocket
  • Shared Worker 多页面共享,Service Worker 缓存离线
  • 适合计算密集型任务,短任务不适合(启动开销)
  • 推荐使用 Worker 池管理多个 Worker

📝 发现内容有误?点击此处直接编辑

← 上一篇 JavaScript Generator 函数与异步生成器
下一篇 → JavaScript 事件循环与微任务/宏任务
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库