你遇到过点击按钮后页面直接"假死"的情况吗?Loading 动图定格、按钮点击无效、甚至浏览器弹出"未响应"警告?别慌,这通常是 JS 主线程被密集计算阻塞了。今天,带你用 Web Worker 把这些重活"踢"出主线程,让你的 Vue3 应用丝滑如初!
😱 案发现场:一段代码让浏览器"脑梗"
在 B 端系统中,我们经常会遇到这种需求:
- 导出 Excel :处理几万条数据的格式化。
- 图像处理 :前端压缩图片或添加水印。
- 复杂算法 :加密解密、大数计算(如斐波那契数列)。
很多同学反手就是直接写在组件里:
javascript
// ❌ 危险操作:在主线程进行 CPU 密集型计算
function expensiveCalculation() {
const result = fibonacci(42); // 这里可能要算好几秒
console.log(result);
}
结果就是: 只要计算还在跑,浏览器的 UI 渲染线程就被挂起。 你的 Loading 圈不转了,用户的鼠标点击没反应了,整个页面像中了定身术一样,就像下图中加载动画卡主了。

💡 救星登场:Web Worker
JavaScript 是单线程的,但浏览器不是! Web Worker 的作用就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。
简单说:主线程负责貌美如花(UI 渲染),Worker 线程负责赚钱养家(脏活累活)。
🛠️ 实战:Vue3 中使用 Web Worker
今天我们就通过一个 斐波那契数列计算 的 Demo,来看看 Worker 到底有多强。
1. 准备 Worker 脚本
首先,我们需要编写一个独立的 JS 文件,它运行在独立的线程中。
javascript
// src/utils/webWorker.js
// 监听主线程发来的消息
self.onmessage = function (e) {
const { type, data } = e.data;
if (type === "FIBONACCI_CALC") {
const start = performance.now();
// 执行耗时计算
const result = fibonacci(data);
const time = performance.now() - start;
// 计算完毕,把结果发回给主线程
self.postMessage({
type,
data: result,
time: time.toFixed(2)
});
}
};
// 递归计算斐波那契数列(故意用性能差的递归来模拟耗时任务)
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
2. 在 Vue 组件中引入
在 Vite 构建的 Vue3 项目中,引入 Worker 非常优雅,只需要加上 ?worker 后缀。
javascript
// src/views/func/performance/webWorker.vue
<script setup>
import { ref } from 'vue';
// ✅ Vite 专属写法,简单粗暴
import MyWorker from "@/utils/webWorker.js?worker";
const calculateNum = ref(42);
const loading = ref(false);
const runWorker = () => {
loading.value = true;
// 1. 实例化 Worker
const worker = new MyWorker();
// 2. 发送任务
worker.postMessage({
type: "FIBONACCI_CALC",
data: calculateNum.value,
});
// 3. 接收结果
worker.onmessage = (e) => {
const { data, time } = e.data;
console.log(`计算结果:${data},耗时:${time}ms`);
// 页面状态照常更新,丝毫不卡!
loading.value = false;
// 4. 用完记得销毁,释放内存
worker.terminate();
};
};
</script>
3. 效果对比
为了直观展示,我做了一个 帧率计数器 。
方案 A(主线程) :点击开始计算,帧率计数器瞬间 停止跳动 ,浏览器卡死,直到计算结束。用户体验极差!❌
方案 B(Worker) :点击开始计算,后台在狂奔,但前台的帧率计数器 依然流畅跳动 ,Loading 动画丝滑旋转。用户体验满分!✅

📝 核心知识点总结
1. 什么时候用 Worker?
①任何超过 50ms 的纯计算任务。
②大文件上传前的切片、Hash 计算。
③复杂数据的过滤、排序、格式化。
④Canvas 图像像素级处理。
2. 注意事项
①DOM 限制 :Worker 内无法操作 DOM(不能 document.getElementById )。
②通信成本 :主线程和 Worker 之间传递数据是通过拷贝而非共享,传输过③大的数据(如几百 MB 的 JSON)本身也会消耗性能。建议使用 Transferable Objects 传输二进制数据。
④同源策略 :Worker 脚本必须遵守同源策略。
3. Vite 黑科技
a.直接作为模块引入。
import Worker from './worker.js?worker'
b.多个标签页共享同一个 Worker。
import SharedWorker from './worker.js?sharedworker'
源码地址
https://gitee.com/benxiaohai1071/bxh-admin-vue3/blob/master/src/views/func/performance/webWorker.vue