前端性能优化-web worker 前言Web Worker 是 HTML5 提供的多线程解决方案可以将耗时的计算逻辑放到独立的后台线程中运行避免阻塞主线程UI 线程解决页面卡顿、交互无响应的问题是前端性能优化的核心手段之一。一、核心基础认知1. 为什么需要 WorkerJavaScript 是单线程语言所有代码都在主线程串行执行。一旦遇到耗时较长的计算大数据排序、复杂算法、大文件解析主线程会被占用导致页面无法响应用户交互、动画掉帧甚至出现 “页面无响应” 提示。Web Worker 的作用就是开辟独立的后台线程和主线程并行运行专门处理耗时任务完成后再把结果传回主线程全程不影响页面渲染和交互。2. 能力与限制支持执行 JS 代码拥有独立的全局上下文使用 fetch / XMLHttpRequest 发送网络请求使用 setTimeout / setInterval 定时器访问 IndexedDB、缓存 API处理二进制数据ArrayBuffer、Blob导入外部 JS 脚本不支持:不能访问 DOM无法操作 document、window、页面元素不能直接调用主线程的变量和函数不能使用 alert、confirm 等浏览器弹窗 API加载的 Worker 文件必须遵守同源策略3. 三类 Worker 对比类型全称生命周期共享范围核心用途专用 WorkerDedicated Web Worker随创建它的页面而生页面关闭即销毁仅属于创建它的单个页面 / 标签页单页面的耗时计算、数据处理最常用共享 WorkerShared Worker同域下多个页面共享最后一个页面关闭才销毁同域下多个标签页共享多标签页数据共享、统一状态管理服务 WorkerService Worker独立于页面浏览器后台常驻同域下所有页面PWA 离线缓存、请求拦截、后台同步二、当前学习重点 Web Worker 基础用法1.创建 worker线程在public公共文件夹下创建heavy-calc.worker.js路径如下内容如下self.onmessage function(e) { const { count } e.data const result heavyCalculate(count) self.postMessage({ result }) } // 加重运算加入三角函数单次循环计算量更大更容易触发长卡顿 function heavyCalculate(num) { let sum 0 for (let i 0; i num; i) { sum Math.sqrt(i) * Math.sin(i) * Math.cos(i) } return sum }2.主线程使用创建 worker 只需要通过 new 调用 Worker(path, options) 构造函数即可它接收两个参数const calcWorker new Worker(/static/workers/heavy-calc.worker.js{})参数说明path有效的js脚本的地址必须遵守同源策略。无效的js地址或者违反同源策略会抛出SECURITY_ERR 类型错误options.type可选用以指定 worker 类型。该值可以是 classic 或 module。 如未指定将使用默认值 classicoptions.credentials可选用以指定 worker 凭证。该值可以是 omit, same-origin或 include。如果未指定或者 type 是 classic将使用默认值 omit (不要求凭证)options.name可选在 DedicatedWorkerGlobalScope 的情况下用来表示 worker 的 scope 的一个 DOMString 值主要用于调试目的。注意如果你想在相对路径中使用worker需要注意导入方式相对路径如图此方法为Vite 原生支持的标准方式会自动处理路径、打包、热更新生产环境也不会出问题完全规避路径坑import HeavyCalcWorker from ./workers/heavy-calc.worker.js?worker const calcWorker new HeavyCalcWorker()3.主线程与 worker 线程都是通过 postMessage 方法来发送消息以及监听 message 事件来接收消息// 主线程 const runWorker () { console.time(Worker计算耗时) calcWorker.postMessage({ count: CALC_COUNT }) } calcWorker.onmessage (e) { result.value e.data.result console.timeEnd(Worker计算耗时) } calcWorker.onerror (err) { console.error(Worker报错, err.message) } // worker线程 self.onmessage function(e) { const { count } e.data const result heavyCalculate(count) self.postMessage({ result }) }ok到这里一个简单的计算worker就创建成功了4.监听错误信息web worker 提供两个事件监听错误error 和 messageerror。这两个事件的区别是:事件触发时机描述errorWorker 脚本执行阶段文件 404、语法错误、变量不存在、代码抛错messageerrorpostMessage 数据传输阶段循环引用、传函数 / DOM、转移后重复使用 ArrayBuffer5.关闭 worker 线程// 组件销毁清理 onUnmounted(() { calcWorker.terminate() self.close() })6. Worker 线程引用其他js文件基于 ESModule模式复杂的计算场景不想把所有代码都放入worker线程时可以直接使用 module 模式初始化 worker 线程。主线程写法// 相对路径导入写法 import HeavyCalcWorker from ./workers/heavy-calc.worker.js?workertypemodule const calcWorker new HeavyCalcWorker() // 绝对路径导入写法 const calcWorker new Worker(/static/workers/heavy-calc.worker.js{ type: module})worker线程import moment from moment console.log(moment().format(YYYY-MM-DD HH:mm:ss))打印结果