javascript中的Web Workers如何使用?_探索javascript多线程编程【教程】

10次阅读

Web Workers 不能直接访问 dom,只能通过 postMessage 与线程通信;支持 SharedArrayBuffer + Atomics 实现共享内存同步;模块化 Worker 需指定 type: ‘module’;需显式调用 terminate() 或 self.close() 管理生命周期。

javascript中的Web Workers如何使用?_探索javascript多线程编程【教程】

Web Workers 不能直接访问 DOM

这是最常踩的坑:Worker 脚本运行在独立线程,documentwindowlocalStorage 等主线程专属对象全部不可用。一旦在 Worker 里写 document.getElementById,会直接报 ReferenceError: document is not defined

Worker 只能做纯计算、数据处理、网络请求(fetch)、定时任务等不涉及 ui 的事。UI 更新必须由主线程完成,Worker 只能通过 postMessage 把结果发回去。

如何创建并通信:Worker 构造函数 + onmessage

主线程中创建 Worker 需传入一个独立 js 文件路径(不能是内联字符串或 Blob URL 在某些旧环境有兼容问题):

const worker = new Worker('path/to/worker.js');

发送数据用 worker.postMessage(data),接收用 worker.onmessage = (e) => { console.log(e.data); };Worker 内部则用 self.onmessage 接收、self.postMessage 发送。

立即学习Java免费学习笔记(深入)”;

注意:postMessage 传输的是结构化克隆(不是深拷贝也不是引用),支持 ArrayBufferTypedArray 等可转移对象,但普通函数、DOM 节点、date 实例等不支持。

SharedArrayBuffer + Atomics 实现线程间同步

默认情况下 Worker 和主线程完全隔离,无法共享内存。若需高频低延迟协作(比如实时音视频处理、游戏逻辑),得启用 SharedArrayBuffer —— 但这要求页面开启跨域隔离(crossorigin 属性 + COOP/COEP 响应头)。

仅靠 SharedArrayBuffer 不够安全,必须配合 Atomics 进行原子操作:

const sab = new SharedArrayBuffer(1024);
const i32 = new Int32Array(sab);
Atomics.add(i32, 0, 1); // 安全递增

漏掉 Atomics 直接读写,会导致竞态条件,结果不可预测。

Worker 中的 importScripts 与模块支持

Worker 传统上用 importScripts('a.js', 'b.js') 加载依赖,但它会阻塞执行、不支持 ES 模块语法。现代方案是使用 new Worker(url, { type: 'module' }),然后在 Worker 文件里直接写 import

const worker = new Worker('./calc-worker.js', { type: 'module' });

对应 Worker 文件中可写:import { heavyCalc } from './utils.mjs';。但要注意:模块 Worker 不支持 importScripts,且所有导入路径必须是相对或绝对 URL(不能是 bare import)。

chrome/firefox 已支持,safari 16.4+ 开始支持,老版本 ios Safari 仍需回退到 importScripts 方案。

主线程和 Worker 的生命周期管理容易被忽略:Worker 实例不会自动销毁,worker.terminate() 必须显式调用;而 Worker 内部调用 self.close() 会立即退出。没关干净的 Worker 会持续占用内存,尤其在单页应用反复创建时。

text=ZqhQzanResources