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线程来处理大量运算,运算完成后返回给主线程,这样不会造成主线程的卡顿问题。

详细来说的话浏览器每个页面(标签页)都会给一个线程,这个线程会用于 htmljscss 一系列加载渲染,当加载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来缓解卡顿、主线程运算压力。

相关推荐
qq_392794483 分钟前
前端缓存策略:强缓存与协商缓存深度剖析
前端·缓存
小美的打工日记39 分钟前
ES6+新特性,var、let 和 const 的区别
前端·javascript·es6
helianying551 小时前
云原生架构下的AI智能编排:ScriptEcho赋能前端开发
前端·人工智能·云原生·架构
@PHARAOH1 小时前
HOW - 基于master的a分支和基于a的b分支合流问题
前端·git·github·分支管理
涔溪1 小时前
有哪些常见的 Vue 错误?
前端·javascript·vue.js
程序猿online1 小时前
前端jquery 实现文本框输入出现自动补全提示功能
前端·javascript·jquery
2401_897579652 小时前
ChatGPT接入苹果全家桶:开启智能新时代
前端·chatgpt
DoraBigHead2 小时前
JavaScript 执行上下文:一场代码背后的权谋与博弈
前端
Narutolxy3 小时前
从传统桌面应用到现代Web前端开发:技术对比与高效迁移指南20250122
前端
摆烂式编程3 小时前
node.js 07.npm下包慢的问题与nrm的使用
前端·npm·node.js