2020-11-25 15:12:38
JavaScript 本身是单线程语言,但可通过 Web Workers(浏览器环境)和 worker_threads 模块(Node.js 环境)实现真正的多线程编程,核心机制为线程隔离与消息传递,必要时可通过 SharedArrayBuffer 实现共享内存。 以下是具体实现方法:
一、浏览器环境:使用 Web Workers 实现多线程Web Workers 允许在后台线程中运行脚本,与主线程并行执行,避免阻塞 UI。主线程与 Worker 线程通过消息传递通信,默认不共享内存。
步骤 1:创建 Worker 文件新建一个 JavaScript 文件(如 worker.js),编写后台运行的代码:
// worker.jsself.onmessage = function(e) { const data = e.data; let result = 0; for (let i = 0; i < data; i++) { result += i; } self.postMessage(result); // 发送结果回主线程};步骤 2:在主线程中启动 Worker在主页面脚本中创建 Worker 实例,发送数据并接收结果:
// main.jsconst worker = new Worker('worker.js');// 接收 Worker 消息worker.onmessage = function(e) { console.log('计算结果:', e.data);};// 错误处理worker.onerror = function(error) { console.error('Worker 错误:', error);};// 发送数据到 Workerworker.postMessage(1000000000); // 计算 0 到 10亿的和若需高效共享数据,可通过 SharedArrayBuffer 分配共享内存,配合 Atomics 操作实现线程安全访问。注意:需配置 CORS 和 COOP/COEP 头以避免安全限制。
主线程创建共享内存并发送
// 创建 4 字节共享内存(存放一个整数)const sharedBuffer = new SharedArrayBuffer(4);const sharedArray = new Int32Array(sharedBuffer);const worker = new Worker('shared-worker.js');worker.postMessage(sharedArray); // 发送共享内存引用// 等待 Worker 修改数据后读取结果setTimeout(() => { console.log('共享数组最终值:', sharedArray[0]);}, 2000);Worker 线程接收并修改共享内存
// shared-worker.jsself.onmessage = function(e) { const sharedArray = e.data; Atomics.add(sharedArray, 0, 42); // 原子操作:将索引 0 的值加 42 Atomics.notify(sharedArray, 0); // 通知其他线程(可选)};Node.js 通过 worker_threads 模块提供多线程能力,支持 SharedArrayBuffer 实现共享内存。
线程隔离性
主线程与 Worker 线程默认不共享全局变量或 DOM,仅通过消息传递(postMessage)通信。
消息内容需可序列化(如基本类型、对象、数组等)。
SharedArrayBuffer 的安全限制
需配置 HTTP 头:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp避免未授权的跨域访问导致共享内存被隔离。
性能权衡
消息传递涉及序列化/反序列化开销,频繁通信可能降低性能。
共享内存(SharedArrayBuffer)适合高频数据交换,但需谨慎处理竞态条件。
错误处理
监听 Worker 的 onerror 或 'error' 事件捕获线程内异常。
在 Node.js 中检查 Worker 的退出码(exit 事件)以诊断崩溃。
浏览器环境
执行耗时计算(如图像处理、大数据分析)而不阻塞 UI。
分割任务到多个线程并行处理(如 Web 版视频编码)。
Node.js 环境
利用多核 CPU 处理 CPU 密集型任务(如机器学习推理)。
替代 child_process 实现更轻量的进程隔离。
通过合理使用 Web Workers 或 worker_threads,JavaScript 可实现高效的多线程编程,关键在于理解线程隔离机制、选择合适的通信方式,并注意安全与性能优化。