web worker 与主线程通过独立事件循环和消息队列异步通信,postmessage 触发结构化克隆后投递消息,双方互不阻塞、无法共享状态,本质是松耦合的异步 rpc。

Web Worker 与主线程的通信不依赖 JavaScript 主线程的事件循环,而是通过独立的、基于消息队列的异步通信机制完成——本质是两个隔离的事件循环之间“跨线程投递消息”,而非共享运行时或调用栈。
Worker 线程拥有自己的独立事件循环
每个 Worker 实例在浏览器中启动一个全新的 JavaScript 执行环境,包含完整的全局对象(self)、自己的调用栈、堆内存,以及**独立的事件循环**。这个循环和主线程互不干扰:主线程卡死(如长同步计算)不会阻塞 Worker 运行,Worker 死循环也不会冻结页面。
Worker 内部的 setTimeout、fetch 回调、message 事件等,都排队在它自己的宏任务队列和微任务队列中,由它自己的事件循环驱动。
postMessage 是跨线程“消息投递”,不是函数调用
worker.postMessage(data) 不会把代码或函数传过去执行,而是将 data **结构化克隆**(structured clone)后,放入目标线程(Worker 或主线程)的**消息队列(Message Queue)** 头部。这一步是同步的,但后续处理完全异步。
例如:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
- 主线程调用
worker.postMessage({id: 1, task: 'calc'})→ 数据被克隆并推入 Worker 的消息队列; - Worker 的事件循环在下一次循环中,从队列中取出该消息,触发
self.onmessage回调(宏任务); - Worker 处理完,再调用
self.postMessage(result)→ 结果被克隆,推入主线程的消息队列; - 主线程事件循环随后执行
worker.onmessage回调。
通信过程绕过主线程事件循环的“繁忙期”
即使主线程正执行一个耗时 500ms 的同步函数,Worker 发来的 message 仍会被写入主线程的消息队列;只是该消息要等到当前同步任务结束、调用栈清空、事件循环回到“取任务”阶段时,才会被取出并触发 onmessage。这正是 Web Worker 实现真正并行、避免 UI 阻塞的关键——通信本身不抢主线程时间片,只在空闲时机响应。
注意:消息内容不能含函数、DOM 节点、undefined 等不可克隆值;若需传递复杂逻辑,应以字符串形式发送代码,Worker 内用 eval 或 new Function 动态执行(需谨慎)。
主线程与 Worker 的事件循环彼此透明
两者无法直接读写对方变量,无法用 await 同步等待对方响应(没有共享 Promise 状态),也无法用 try/catch 捕获对方抛出的错误。所有交互必须显式通过 postMessage / onmessage + 自定义协议(如带 type 和 id 的消息体)来协调,本质上是一种松耦合的异步 RPC 模式。
可借助 Promise + MessageChannel 封装成更直观的请求响应流,但底层仍是两次独立的事件循环调度。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










