web-worker使用与应用

我的博客原文

@author: 郭瑞峰 @createTime: 2023/08/31 @updateTime: 2023/09/03

前言

之前支援其他组时候遇见过一个很难受的卡顿问题

因为后端给了几十万组数据,要前端经过多次复杂算法算出结果后展示在 矩形树图 中,运算量大到能把标签页卡顿20秒。

还好之前了解过web-worker,所以说我就想到用web-worker优化卡顿。

先放demo把,大家可以先去感受感受把,若没有任何卡顿,恭喜你了,你用的CPU性能超群(体验就不会这么明显)。

项目地址:web-worker demo

线上demo: 线上demo

web-worker 原理

简单来说,页面需要大量运算,运算需要一定时间时,可以让主线程申请一个Worker线程,由Worker线程来处理大量运算,运算完成后返回给主线程,这样不会造成主线程的卡顿问题。

详细来说的话浏览器每个页面(标签页)都会给一个线程,这个线程会用于 html、js、css 一系列加载渲染,当加载js时候会暂停后续标签运行(若script设置async,这个就不会阻塞后续运行),这个时候如果js代码出现庞大运算,计算消耗时间过长就会影响后续响应,为了不影响后续标签或其他事件响应,就需要一个手段让计算操作在其他线程中运行。

(严格来说,浏览器每个标签页都会分配至少一个进程,为了防止单个页签崩溃后影响其他页签,之后就是在当前进程中分配线程,详情请见 掘金大佬归纳)

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,这个是前端性能优化工具,操作前记录 ,操作完成后停止,等待片刻就会生成性能报告。

可以参考这个大佬写的东东

如果生成的报告中scripting时间超过3秒,并且页面域很严重卡顿现象 ,建议使用web-worker来缓解卡顿、主线程运算压力。

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师3 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学3 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端