Loading... > @author: 郭瑞峰 > @createTime: 2023/08/31 > @updateTime: 2023/09/03 ## 前言 之前支援其他组时候遇见过一个很难受的卡顿问题 因为后端给了几十万组数据,要前端经过多次复杂算法算出结果后展示在 矩形树图 中,运算量大到能把标签页卡顿20秒。 还好之前了解过`web-worker`,所以说我就想到用`web-worker`优化卡顿。 先放`demo`把,大家可以先去感受感受把,若没有任何卡顿,恭喜你了,你用的CPU性能超群(体验就不会这么明显)。 项目地址:[web-worker demo](https://github.com/xiaoxiaoxuan114-stduy/web-worker/tree/main "web-worker demo") 线上demo: [线上demo](https://web-worker-five.vercel.app/ "线上demo")  ## web-worker 原理 简单来说,页面需要大量运算,运算需要一定时间时,可以让`主线程`申请一个`Worker`线程,由`Worker`线程来处理大量运算,运算完成后返回给`主线程`,这样不会造成`主线程`的卡顿问题。 详细来说的话浏览器每个页面(标签页)都会给一个线程,这个线程会用于 `html`、`js`、`css` 一系列加载渲染,当加载`js`时候会暂停后续标签运行(若`script`设置`async`,这个就不会阻塞后续运行),这个时候如果`js`代码出现庞大运算,计算消耗时间过长就会影响后续响应,为了不影响后续标签或其他事件响应,就需要一个手段让计算操作在其他线程中运行。 (严格来说,浏览器每个标签页都会分配至少一个进程,为了防止单个页签崩溃后影响其他页签,之后就是在当前进程中分配线程,详情请见 [掘金大佬归纳](https://juejin.cn/post/6991849728493256741 "掘金大佬归纳")) ## web-worker 入手 `web-worker`分为两部分,`主线程`和`Worker`线程,故因此会有`主线程`引入注册使用销毁`Worker`线程的一套流程,下面就是一个简单的`demo`来实现`web-worker`。 当然,你也可以结合我的`demo`来看。 ### 主线程注册使用销毁 worker线程 * react 使用示例 ```typescript import React, { useState, useEffect } from 'react' const Havefun: React.FC = () => { const [worker, setWorker] = useState<Worker | null>() useEffect(() => { // 初始化worker线程,必须通过这种方法引入worker.js文件 setWorker(new Worker( new URL('XXX.worker.js', import.meta.url), { type: 'module' } )) // 如果使用next框架的话,请注意区分node和browser环境,下面是next的例子 /* setWorker(typeof window !== 'undefined' && window.Worker ? new Worker( new URL('XXX.worker.js', import.meta.url), { type: 'module' } ) : null) */ return () => { // 销毁事件 worker?.removeEventListener('message', workerListener) // 销毁worker线程 worker?.terminate() } }, []) // worker 返回事件,便于注册和销毁 const workerListener = ({ data }: any) => { console.log(data) } const useWorker = () => { worker?.addEventListener('message', workerListener) worker?.postMessage('hello, this is main thread') } return (<button onClick={useWorker}>call web-worker</button>) } Havefun.displayName = 'Havefun' export default Havefun ``` * vue ```html <script setup lang="ts"> import { onUnmounted } from 'vue' const worker: Worker | null = new Worker( new URL('XXX.worker.js', import.meta.url), { type: 'module' } ) // 如果使用nuxt框架的话,请注意区分node和browser环境,下面是nuxt的例子 /* const worker = typeof window !== 'undefined' && window.Worker ? new Worker( new URL('XXX.worker.js', import.meta.url), { type: 'module' } ) : null */ worker?.addEventListener('message', ({ data }) => { console.log(data) }) onUnmounted(() => { worker?.terminate() }) const useWorker = () => { worker?.postMessage('hello, this is main thread') </script> <template> <button @click="useWorker">call web-worker</button> </template> ``` ### worker文件编写 ```javascript // 注意:该文件是直接进入浏览器运行的,建议使用javascript而不是typescript // test.worker.js self.addEventListener('message', ({ data }) => { console.log(data) self.postMessage('hello, this is worker thread') }) ``` ### 运行示例 > 我用的是next框架测试  ## web-worker应用 * `webgl` 或者 `ffmpeg` 这种2D3D图像渲染、视频处理需要处理运算大量数据 * 页面因为一些**超级大的运算引起的卡顿** ### 如何判断页面是否需要web-worker 在开发工具中找到`performance`,这个是前端性能优化工具,**操作前记录**,**操作完成后停止**,等待片刻就会生成性能报告。   [可以参考这个大佬写的东东](https://juejin.cn/post/7223668409506431037 "可以参考这个大佬写的东东") 如果生成的报告中`scripting`时间**超过3秒,并且页面域很严重卡顿现象**,建议使用`web-worker`来缓解卡顿、主线程运算压力。  最后修改:2024 年 11 月 27 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏
1 条评论
这篇文章如同一首动人的乐章,触动了读者内心深处的柔软。