告别页面卡死!Vue3 + WebWorker 性能优化实战

你遇到过点击按钮后页面直接"假死"的情况吗?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

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
liangshanbo12154 天前
React 性能优化实战
性能优化·react
mmsx4 天前
Android GIS系列 内存加锁、SQLite 开事务:矢量数据集双层并发设计
android·性能优化·app
Pioneer000015 天前
我用 Redis + 网关做多模型 API 路由:缓存命中率 95%+ 的工程实践
人工智能·redis·后端·缓存·性能优化·架构
ZFJ_张福杰5 天前
【Flutter】Flutter 中有哪些耗时操作?从 UI 卡顿到 Isolate 性能优化
flutter·性能优化·卡顿·isolate
政企项目老覃5 天前
金融转账“幽灵失败“排查实录:从本地消息表到 Seata TCC 的选型与权衡
数据库·程序人生·性能优化·数据分析·系统架构
爱喝水的鱼丶5 天前
SAP-ABAP:MM 模块供应商主数据开发:字段扩展、分级管控与同步接口开发
开发语言·性能优化·接口·sap·abap·增强·经验交流
贾伟康5 天前
【HarmonyOS 7新能力|050】Core File Kit mmap工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·文件系统·mmap
贾伟康5 天前
【HarmonyOS 7新能力|045】LazyLayoutAlgorithm工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·arkui·懒加载
打工仔折腾 AI5 天前
数据库上 K8s 之后谁来管?拆解金仓 KES-Operator 的声明式运维方案
人工智能·后端·python·性能优化·ai agent 实战