一、主线程核心关键操作(配合 useEffect + useRef,截图里的代码架构)
1. useRef 缓存 Worker 实例(必做)
jsx
const workerRef = useRef(null)
- 关键作用:Worker 实例存在 ref,不会触发组件重渲染;
- 避坑:如果直接用普通变量存,组件每次渲染重复 new Worker,疯狂创建线程内存爆炸。
2. useEffect 管理 Worker 完整生命周期(最核心)
(1)挂载时:初始化 Worker
jsx
useEffect(() => {
// 关键1:Vite下正确加载worker文件路径
const worker = new Worker(new URL('./worker.js', import.meta.url))
workerRef.current = worker
// 关键2:绑定子线程返回消息的监听
worker.onmessage = (e) => {
setResult(e.data.result)
}
// 关键3:监听线程报错,防止无声崩溃
worker.onerror = (err) => {
console.error('Worker异常', err)
}
// 关键4:返回清理函数(卸载销毁)
return () => {
worker.terminate()
}
}, [])
(2)清理销毁 worker.terminate() 必写
- 关键:组件卸载、页面关闭时立刻终止后台线程;
- 不做的后果:Worker 持续后台占用 CPU,内存泄漏,刷新页面旧线程还在跑。
3. 主线程发起计算:postMessage 下发任务
jsx
const handleCalc = () => {
// 向独立子线程发送计算参数,主线程立刻释放,不阻塞
workerRef.current.postMessage(500000000)
}
- 关键:
postMessage是异步非阻塞调用,发完消息主线程直接继续渲染页面,不会等循环跑完。
二、Worker 子线程关键操作(worker.js)
1. 全局监听主线程消息 self.onmessage
js
// self 代表Worker线程全局对象,不能用window
self.onmessage = (e) => {
// e.data 接收主线程传过来的计算参数
const max = e.data
let sum = 0
// 重度循环完全在独立子线程执行,不占用DOM渲染主线程
for(let i=0; i<max; i++){
sum += max * i
}
// 计算完成,把结果传回主线程
self.postMessage({ result: sum })
}
关键点:
- Worker 没有
window,只能用self; - 所有循环、复杂 JSON 解析、矩阵运算全部写在
onmessage回调内部; - 禁止操作 DOM、alert、document、fetch 同步阻塞 API。
2. 计算完成回调 self.postMessage 回传结果
- 线程隔离无法直接修改 React state,只能通过消息序列化传递数据;
- 主线程
onmessage收到数据后再执行setResult更新页面。
三、保证「页面不卡顿」的底层关键机制操作
- 线程隔离分配浏览器向操作系统申请全新后台工作线程,和渲染主线程分属两个独立执行栈,CPU 多核可并行调度,计算与渲染互不抢占。
- 非阻塞消息通信模型
postMessage采用结构化克隆算法异步传参,主线程发送任务后立即释放,不会同步等待计算结束。 - 渲染主线程全程空闲按钮点击、滚动、输入、DOM 更新、React 重渲染逻辑全程不受循环运算干扰,交互事件可以实时响应。
四、高频避坑关键操作(决定能不能稳定流畅)
- 不要在组件顶层直接
new Worker:每次重渲染新建线程; - 必须在 useEffect 清理函数调用
terminate(); - 超大二进制数据用
Transferable转移所有权,避免大对象拷贝卡顿; - Worker 内部禁止任何 DOM/BOM 操作,否则直接报错线程失效;
- 依赖项变化需要重建 Worker 时,useEffect 会先执行旧线程 terminate,再创建新实例。
极简流程总结(核心操作链路)
useRef存 Worker 实例 → 2.useEffect挂载创建线程、绑定 onmessage 监听 → 3. 点击事件postMessage下发计算任务 → 4. Worker 线程self.onmessage执行重度循环 → 5. 计算完成self.postMessage返回结果 → 6. 主线程接收数据更新 state → 7. 组件卸载自动terminate销毁线程释放资源。