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来缓解卡顿、主线程运算压力。

相关推荐
Z_ One Dream16 分钟前
css 在 hover 子元素时,不要让父元素触发 hover 效果
前端·javascript·css
码农幻想梦5 小时前
实验九 视图的使用
前端·数据库·oracle
开心工作室_kaic7 小时前
ssm010基于ssm的新能源汽车在线租赁管理系统(论文+源码)_kaic
java·前端·spring boot·后端·汽车
大力水手~8 小时前
css之loading旋转加载
前端·javascript·css
Nguhyb8 小时前
-XSS-
前端·xss
前端郭德纲8 小时前
深入浅出ES6 Promise
前端·javascript·es6
就爱敲代码8 小时前
ES6 运算符的扩展
前端·ecmascript·es6
王哲晓9 小时前
第六章 Vue计算属性之computed
前端·javascript·vue.js
究极无敌暴龙战神X9 小时前
CSS复习2
前端·javascript·css
风清扬_jd9 小时前
Chromium HTML5 新的 Input 类型week对应c++
前端·c++·html5