vue3中使用Web Worker多线程

文章目录

  • 问题描述
  • Web Worker的作用
  • 在vue3中使用
      • ❀安装worker-loader
      • ❀配置webpack
      • ❀使用
        • ts项目注意事项
  • 获取项目Demo
      • ❀CSDN:
      • ❀Gitee:

问题描述

最近在做vue3的项目中,遇到了计算量庞大导致页面响应缓慢的问题,正好每个计算任务的结果不需要汇总,所以想到了以多线程的形式去执行每个计算任务。但是通过一轮google、baidu都没有找到vue3的案例,还好在外网的一篇案例中嗅到了一丝可能。


Web Worker的作用

大佬可以跳过, 对于Web Worker多线程可能有很多小伙伴还不知道是干嘛的,所以我先举一个列子让大家知道它大概是用来做什么的。

提示:用到的console如果看不懂的,可以到这篇文章学习:传送门

①洗完澡后再洗衣服: 在没有洗衣机(Worker)前,通常都是先洗完澡后再手洗衣服(这里我除外,我都是踩着衣服一起洗澡的),这样我们每天都要花费不少时间在洗澡和洗衣服上,花费时长为:洗澡所用时长+洗衣服所用时长。相当于下面这段代码:

console.time('一共花了多少时长')
console.time('洗澡所用时长')
let length_1 = 300000000;
let sum1 = 0
for (let i = 0; i <= length_1; i++) {
    sum1 += i
}
console.log('%c循环1执行完:' + sum1, 'color:green')
console.timeEnd('洗澡所用时长')
console.time('洗衣服所用时长')
let length_2 = 200000000;
let sum2 = 0
for (let i = 0; i <= length_2; i++) {
    sum2 += i
}
console.log('%c循环2执行完:' + sum2, 'color:green')
console.timeEnd('洗衣服所用时长')
console.timeEnd('一共花了多少时长')
// 循环1执行完:45000000067108860
// 洗澡所用时长: 2712.139892578125 ms
// 循环2执行完:20000000067108864
// 洗衣服所用时长: 1751.049072265625 ms
// 一共花了多少时长: 4463.2490234375 ms

GIF输出效果:(从结果可以看到大概第2.7秒循环1执行完了,接着大概到了第4.5秒后循环2才执行完,所以从中可以看出循环1阻塞了循环2,所以此时花费时长为:循环1+循环2)
vue3中使用Web Worker多线程_第1张图片

②把衣服放到洗衣机后洗澡: 当我们拥有洗衣机(Worker)后,就可以把衣服放到洗衣机后愉快的洗澡了,此时为异步操作,那么这时花费的总时长取决于谁更后洗完了,花费时长为:Math.max(洗澡所用时长,洗衣服所用时长)。相当于下面的代码:

本地工作目录:

文件夹
	|-index.html
	|-worker.js

index.html:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Workertitle>
head>

<body>

body>
<script>
    console.time('洗衣机洗完衣服了,所用时长')
    var worker = new Worker("./worker.js"); // 开启副线程
    let length_1 = 300000000;
    let sum1 = 0
    worker.postMessage(length_1); // 发送消息给副线程
    worker.onmessage = e => { // 监听副线程返回的消息
        sum1 = e.data
        console.log('%c循环1执行完了:' + e.data, 'color:green')
        console.timeEnd('洗衣机洗完衣服了,所用时长')
        worker.terminate() // 关闭线程
    }
    console.time('洗完澡了,所用时长')
    let length_2 = 200000000;
    let sum2 = 0
    for (let i = 0; i <= length_2; i++) {
        sum2 += i
    }
    console.log('%c循环2执行完了:' + sum2, 'color:green')
    console.timeEnd('洗完澡了,所用时长')
script>

html>

worker.js:

self.onmessage = function (e) { //监听主线程发过来的消息
    let length_1 = e.data
    let sum = 0
    for (let i = 0; i <= length_1; i++) {
        sum += i
    }
    self.postMessage(sum); // 将信息发送到主线程上
}

GIF输出效果:(从结果可以看到大概第1.9秒循环2执行完了,紧接着接着大概第2.4秒后循环1也执行完了,当我们把循环1放到线程上执行时并没有阻塞后续的循环2,因为循环2循环时长短所以先打印出来了,因此此时花费总时长为:循环1)
vue3中使用Web Worker多线程_第2张图片
虽然折腾这么久后只省了几秒钟,但是当项目计算量越来越大,多线程的优势就会变得特变明显了。


在vue3中使用

在vue项目中,如果直接使用Web Worker,会遇到worker文件路径与打包解析的问题,在做vue2.x项目时可以使用vue-worker插件去优雅的使用多线程,但我当我尝试在vue3中使用时,它依赖的simple-web-worker库会报Object.defineProperty called on non-object的错误,应该是vue3把Vue全局对象给模块化了导致它拿不到对象,所以我放弃它了。经过一番查找,我发现还有另外一个方案,就是worker-loader插件,因为它是一个解析器所以我初步判断是可以在vue3中使用的,但是看过很多相关的博文,都没有能够在vue3中正常使用它(╯°Д°)╯︵┻━┻,最后终于在这篇外网博文中找到了可用代码,成功在vue3中跑起来了(T ^ T)

❀安装worker-loader

好了说了这么多,开始进入正题,我们先运行npm安装worker-loader

npm install worker-loader

安装成功后在package.json文件的dependencies中可以看到
vue3中使用Web Worker多线程_第3张图片

❀配置webpack

vue.config.js文件的defineConfig里加上配置参数

  chainWebpack: config => {
    config.module
      .rule('worker-loader')
      .test(/\.worker\.js$/)
      .use({
        loader: 'worker-loader',
        options: {
          inline: true
        }
      })
      .loader('worker-loader')
      .end()
  }

详细截图:
vue3中使用Web Worker多线程_第4张图片

❀使用

先在src目录下新建workers文件夹,接着在里面新建worker.js,在js文件里添加下面的测试代码:

addEventListener('message', e => {
    const { data } = e
    console.log(data)
    setTimeout(() => {
        return postMessage('线程完成')
    }, 1000)
})
export default {}

详细截图:
vue3中使用Web Worker多线程_第5张图片
之后就可以新建一个vue文件,加入下面代码进行测试:

引入js文件时需要使用worker-loader!@并且路径是从src目录下开始数层级的,并非你执行的vue文件开始,这就是我一直不能正常跑起来的原因。

<template>
  <div>
    <h1>vue3-Workerh1>
    <button @click="openWorker">开启线程button>
    <p>F12打开浏览器控制台查看效果p>
  div>
template>

<script setup>
import Worker from 'worker-loader!@/workers/worker'
const openWorker = () => {
  const worker = new Worker()
  worker.postMessage('开启线程')
  worker.onmessage = e => {
    console.log(e.data)
    setTimeout(() => {
      worker.postMessage('线程关闭')
      worker.terminate()
    }, 1000)
  }
}
script>

为了方便,我就直接用官方模板的HelloWorld.vue进行测试了:
vue3中使用Web Worker多线程_第6张图片
GIF运行效果:(在控制台Console中可以看到线程的打印状态,源代码Sources的线程Threads中可以看到所有已开启的线程,手速快的按shift+esc也能看到)

vue3中使用Web Worker多线程_第7张图片

ts项目注意事项

当你把代码写成typeScript时(因为线程跑完后我返回了字符串,所以event里的data需要声明为string),你会发现引入的ts文件路径会报波浪线:
vue3中使用Web Worker多线程_第8张图片
这时我们需要在shims-vue.d.ts文件中声明一下文件路径,直接为所有.ts文件声明也行:
vue3中使用Web Worker多线程_第9张图片


获取项目Demo

有积分的交一下公粮,没有的话到Gitee下载就好

❀CSDN:

vue3-web-worker:传送门
vue3-ts-web-worker:传送门

❀Gitee:

vue3-web-worker:传送门
vue3-ts-web-worker:传送门

你可能感兴趣的:(Vue框架,vue3多线程,vue3,webWorker,vue3,web-worker,web-worker,vue3)