当前位置: 首页 > news >正文

从单线程到多线程:项目实战web Worker线程使用总结

目录

  • 从单线程到多线程:项目实战web Worker线程使用总结
    • 前言
      • Web Worker 是什么
      • Web Worker 作用与用处
      • js单线程问题
      • 异步处理一个耗时计算
      • 创建Web Worker
        • 第一步、我们需要创建一个单独的JavaScript文件
        • 第二步、在主线程中启动Worker
      • web Worker主子线程监听通信
        • 主线程发送消息给Worker
        • Worker线程接收并处理消息
        • Worker发送回主线程
        • 主线程接收Worker消息
      • web Worker 错误监听信息
        • 在主线程中监听Worker错误
        • 在Worker内部抛出错误
      • 关闭 web Worker
        • 在主线程中关闭Worker
        • 在Worker内部自我终止
      • 主线程和`Worker`线程可传递哪些类型数据
      • webworker兼容性问题
      • 模块的引入
      • 基本使用
      • webworker使用注意事项
      • webworeker的常见应用
      • 案例一、解决canvas滤镜处理卡顿问题
      • 案例而、解决十万条数据导出excel表格卡顿问题

从单线程到多线程:项目实战web Worker线程使用总结

前言

        在最近的开发过程中,我频繁地遇到了需要处理大量列表数据、大屏展示的数据以及Canvas数据的任务。在这些情况下,JavaScript的单线程特性成了一个瓶颈——每当执行复杂的数据处理任务时,网页就会出现堵塞,必须等待数据处理完毕才能继续加载页面。这不仅导致了其他DOM元素在此期间无法操作,还使得整个网页变得卡顿,严重影响了用户体验。
        为了解决这个问题,我决定采用Web Worker技术来优化数据处理流程。通过使用Web Worker,可以在后台线程中执行耗时的数据处理任务,从而避免阻塞主线程。这样一来,即使面对长时间运行的数据处理任务,也能确保网页的流畅性和响应性,极大地提升了用户体验。

Web Worker 是什么

Web WorkerHTML5 引入的一种技术,它允许在后台运行 JavaScript 代码而不影响页面的性能。JavaScript 历来是单线程执行的,这意味着所有的任务都在同一个线程上顺序执行。如果某个操作需要较长时间完成(比如大数据量处理、复杂计算等),那么整个页面可能会暂时冻结,直到该操作完成。
Web Worker 提供了一种方式让开发者可以在后台创建一个或多个额外的 JavaScript线程,这些线程可以与主线程并行工作,从而不会阻塞用户界面。通过这种方式,Web Worker 可以帮助提升 Web 应用程序的响应速度和用户体验。

Web Worker 作用与用处

由于web Worker允许在后台执行耗时任务,这使前端UI不会因为复杂的计算出现卡顿,比如在大量的数据分析,图像处理,像素计算时候,可以将这些数据处理逻辑交给web Worker线程来处理。
还可以支持长期运行的任务,那些可能需要很长时间才能完成的操作,比如文件读取,网络请求等都可以使用webWorker线程在后台持续运行,而不会干扰到用户的其他交互行为。

  1. canvas图像滤镜等处理。
  2. 数据清洗聚合等。
  3. 大量排程数据处理。
  4. 导出10W+数据为Excel表格。

js单线程问题

众所周知,js一直被说不擅长计算,计算是同步的,大规模计算会让js主线程阻塞,主线程阻塞的结果就是界面完全卡死。异步只是把任务发布出去等着,后面还是会拉到主线程执行的,异步不可能在异步列队自己执行,所以一个耗时很高的操作无论你做不做异步,始终会卡死页面。

异步处理一个耗时计算

在这里插入图片描述
假设这个耗时任务必须消耗两秒去计算,我们主线程必须消耗两秒去计算,主线程永远不可能躲开这两秒的计算时间,只能通过切片等操作,把这两秒切分成好几个几十毫秒,一点一点计算来解决卡顿的问题。
webworker是真正的多线程,开一条支线,让他计算,然后把结果返回
在这里插入图片描述

创建Web Worker

第一步、我们需要创建一个单独的JavaScript文件

我们需要创建一个单独的JavaScript文件,这个文件将在Worker线程中运行。

// worker.js
self.onmessage = function(event) {console.log("收到消息:" + event.data);let result = "Worker返回结果: " + event.data.toUpperCase();postMessage(result);
};
第二步、在主线程中启动Worker
 const worker = new Worker('worker.js');
worker.postMessage("Hello Worker");worker.onmessage = function(event) {console.log("来自Worker的消息:" + event.data);};

web Worker主子线程监听通信

Web Worker 使用postMessage()onmessage 进行线程间通信。这种通信方式基于事件模型。

主线程发送消息给Worker
worker.postMessage("Hello from main thread");
Worker线程接收并处理消息
self.onmessage = function(event) {console.log("Worker收到消息:" + event.data);// 处理逻辑...self.postMessage("Worker已处理完成");
};
Worker发送回主线程
self.postMessage("这是Worker的返回值");
主线程接收Worker消息
worker.onmessage = function(event) {console.log("主线程收到Worker消息:" + event.data);
};

web Worker 错误监听信息

为了确保Worker的稳定运行,我们可以监听错误信息。

在主线程中监听Worker错误
worker.onerror = function(error) {console.error("Worker发生错误:" + error.message);console.error("错误文件:" + error.filename);console.error("错误行号:" + error.lineno);
};
在Worker内部抛出错误
// worker.js
self.onmessage = function(event) {try {// 模拟错误throw new Error("这是一个测试错误");} catch (e) {postMessage("捕获到错误:" + e.message);}
};

关闭 web Worker

当不再需要Worker时,应该及时关闭它以释放资源。

在主线程中关闭Worker
worker.terminate(); // 立即终止Worker
在Worker内部自我终止
self.close(); // Worker线程内部调用

主线程和Worker线程可传递哪些类型数据

以下是支持的数据类型:

- 基本类型(String, Number, Boolean)	
- 数组(Array- 对象(Object)	
- Date对象	
- Map / Set	
- ArrayBuffer	
- ImageData	
- Transferable对象(如ArrayBuffer)	

webworker兼容性问题

在这里插入图片描述

模块的引入

es6的情况下,必须是网络地址引入,这个网络地址可以跨域

importScripts('http://localhost:9528/process.js');
console.log("a1", a1)

es6的情况下,在new Worker()的第二个参数指定module类型

this.worker1 = new Worker("http://localhost:9528/ai-screen/list.js", {type: "module"});

加上后可以写成,worker.js可写成

import { a1 } from 'http://localhost:9528/process.js'
console.log("a1", a1)

在这里插入图片描述

基本使用

主线程监听worker1发过来的消息,子线程监听主线程发过来的消息,主线程发送一个消息给子线程,子线程打印"收到"并将返回结果给主线程,主线程接收到结果后打印"辛苦你了worker1:子线程返回的结果结果"
在这里插入图片描述
在这里插入图片描述

webworker使用注意事项

通过上面的基本使用,需要注意以下四个问题:

  1. webworker不能使用本地文件,必须是网络上的同源文件。
  2. webworker不能使用window上的dom操作,也不能获取dom对象,dom相关的东西只有主线程有,只能做一些计算相关的操作。
  3. 有的东西是无法通过主线程传递给子线程的,比如方法,dom节点,一些对象里的特殊设置(freeze,getter,setter这些),所以vue的响应式对象不能传递的
  4. 模块的引入

webworeker的常见应用

因为webworker的限制,就别想多线程渲染dom了,因为它根本无法创建dom,所以vuereact框架没有考虑webworkerwebworker的常见主要是耗时的计算,随着webgl,canvas的能力加入,web前端越来越多的可视化操作,比如在线滤镜,在线绘图,web游戏等,这些都是非常消耗计算的,一些后台管理也会涉及到一些,最常见的就是一些电子表单,大量的数据大量的计算,比如10W条数据导出为excel表格。

案例一、解决canvas滤镜处理卡顿问题

案例一、使用canvas进行图片过滤,图片上放有个input标签,图片过滤需要处理很多像素点数据,由于js单线程机制,会导致在图片过滤的过程中进行堵塞,网页就会卡顿,直到每个像素点都完全过滤好为止,接下来通过webWorker进行处理,进行过滤的同时其他dom元素不会被卡顿。

<template><div><div style="display: flex"><el-inputstyle="width: 170px"placeholder="请输入"v-model="inputValue"></el-input><el-button @click="imghandler">过滤</el-button></div><canvas id="imgCanvas" width="1800" height="900"> </canvas></div>
</template><script>
import { Input } from "element-ui";export default {data() {return {inputValue: "",worker1: null,canvas: null,myContext: null,img: null,imageData: null,};},created() {this.$nextTick(() => {let img = new Image();img.src = require("../../src/assets/daskBg.jpg");img.onload = () => {// 使用箭头函数保持外部的 `this` 不变this.canvas = document.getElementById("imgCanvas");this.myContext = this.canvas.getContext("2d");this.myContext.drawImage(img, 0, 0, 1800, 900);this.imageData = this.myContext.getImageData(0, 0, 1800, 900);};});},methods: {// 滤镜函数 - 灰色滤镜imghandler() {if (!this.imageData) {console.error("Image data is not available.");return;}let imageData = this.imageData;let data = imageData.data;let worker1 = new Worker("http://localhost:9528/imageProcess.js");worker1.postMessage(data);worker1.addEventListener("message", (event) => {const processedImageData = new ImageData(new Uint8ClampedArray(event.data),imageData.width,imageData.height);this.myContext.putImageData(processedImageData, 0, 0);});// 将修改后的图像数据放回画布上},},
};
</script><style scoped></style>

imageProcess.js过滤处理文件:

self.addEventListener("message", function (e) {if (e.data.length > 0) {let data = e.datafor (let i = 0; i < data.length; i += 4) {// 增加多余循环 6480000*100for (let j = 0; j < 100; j++) {// 每个像素有四个值: R, G, B, Alet avg = (data[i] + data[i + 1] + data[i + 2]) / 3; // 计算灰度平均值data[i] = avg; // Reddata[i + 1] = avg; // Greendata[i + 2] = avg; // Blue}}self.postMessage(data);}
})

使用之前的效果:明显堵塞
在这里插入图片描述

使用之后的效果:
在这里插入图片描述

案例而、解决十万条数据导出excel表格卡顿问题

当前有10W条数据,需要进行导出excel文件操作,正常点击导出会出现页面堵塞卡顿,无法操作其他DOM,引入webWorker的情况下就不会出现类似此情况。

<template><div><div style="display: flex"><el-inputstyle="width: 170px"placeholder="请输入"v-model="inputValue"></el-input><el-button @click="importClick">导出</el-button></div></div>
</template><script>
import { Input } from "element-ui";
import { writeFile, utils } from "xlsx";export default {data() {return {inputValue: "",worker1: null,arr: [],};},created() {this.$nextTick(() => {this.worker1 = new Worker("http://localhost:9528/work.js");this.worker1.onmessage = (e) => {writeFile(e.data, "test.xlsx");};this.arr = [];});},methods: {importClick() {this.worker1.postMessage("");},},
};
</script><style scoped></style>

work.js

importScripts("http://localhost:9528/xlsx.js")
let arr = []
for (let i = 0; i < 100000; i++) {arr.push({id: i,name: `name${i}`,age: i,sex: i % 2 === 0 ? "男" : "女",a: i * 2,b: i / 2,c: 1 + 2,d: 11,e: 123,f: 2323,});
}
self.addEventListener("message", function (e) {const sheet = XLSX.utils.json_to_sheet(arr);const workbook = XLSX.utils.book_new();XLSX.utils.book_append_sheet(workbook, sheet, "sheet1");this.self.postMessage(workbook)
})

效果:
在这里插入图片描述

相关文章:

  • 联合建模组织学和分子标记用于癌症分类|文献速递-深度学习医疗AI最新文献
  • 2025 后端自学UNIAPP【项目实战:旅游项目】5、个人中心页面:微信登录,同意授权,获取用户信息
  • 大模型智能体与 React Flow:构建智能化可视化交互系统的技术范式
  • Node.js 安装 + React Flow 快速入门:环境安装与项目搭建
  • #跟着若城学鸿蒙# 鸿蒙-卡证识别
  • 【搭建Node-RED + MQTT Broker实现AI大模型交互】
  • 游戏引擎学习第283天:“让‘Standing-on’成为一个更严谨的概念
  • 算法分析:蛮力法
  • 【PX4飞控】在 Matlab Simulink 中使用 Mavlink 协议与 PX4 飞行器进行交互
  • Java应用OOM排查:面试通关“三部曲”心法
  • 使用LoRA微调Qwen2.5-VL-7B-Instruct完成电气主接线图识别
  • EasyExcel集成使用总结与完整示例
  • 毕设设计 | 管理系统图例
  • 从 Excel 到 Data.olllo:数据分析师的提效之路
  • 海康立体相机3DMVS软件使用不同工作模式介绍
  • 完成反射宇宙的最后一块拼图:泛型集合
  • idea经常卡顿解决办法
  • Android Studio中Gradle 7.0上下项目配置及镜像修改
  • 气胸复查重点提问清单 ,怎样平衡检查必要性和辐射影响?
  • 低成本高效图像生成:GPUGeek和ComfyUI的强强联合
  • 百色一女子称家委会强制排班被迫抱婴儿校门口站岗?区教育局:自愿参与
  • 美国与卡塔尔签署超2435亿美元经济及军事合作协议
  • 国台办:实现祖国完全统一是大势所趋、大义所在、民心所向
  • 京东CEO许冉:外卖日单量接近2000万单,看到外卖对平台拉动和转化效应
  • 北京“准80后”干部兰天跨省份调任新疆生态环境厅副厅长
  • 朝着解决问题的正确方向迈进——中美经贸高层会谈牵动世界目光