web worker在生成Excel场景下的简单使用

1.介绍

Web Workers 是 HTML5 中引入的技术,允许在浏览器中创建多线程 JavaScript 执行环境。这使得你可以在主线程之外创建一个或多个后台线程,以执行复杂的任务,而不会阻塞主线程的执行。Web Workers 对于处理需要大量计算或长时间运行的任务非常有用,因为它们可以提高网页性能和响应速度。

2.使用

当我们有任务需要大量的计算,并且不想堵塞用户的正常使用的情况,就可以选择采用webWorker

基本用法

在主进程中调用Worker()构造函数,会创建一个新的webWorker线程,构造函数的参数必须是一个脚本文件(同源限制),是无法读取本地文件的
var worker = new Worker('work.js');

在项目中,可以通过以下方式设置脚本文件:


1.选择直接将文件放置服务器对应静态目录下

2.通过Blob将字符串转化成 Blob对象,再通过URL.createObjectURL生成对象的URL,供Worker()构造函数使用(不推荐)

javascript 复制代码
new Worker(
    URL.createObjectURL(
        new Blob([
            `
            console.log('hello world');
      `,
        ])
    )
)

3.通过打包工具创建(推荐)

webpack中可以使用worker-loader去处理 xxx.worker.js 文件

vite中不需要任何工具:

通过import MyWorker from "./utils/uploadExcel.js?worker"在引入时追加?worker

也可通过 new Worker(new URL('./utils/uploadExcel.js?raw', import.meta.url))来获取文件的原始内容的方式引入。


基本的使用教程,可以去看一下阮一峰老师的博客,推荐一下,这里就不水字数了
Web Worker 使用教程 - 阮一峰的网络日志

3.场景演示

下面我将会简单演示一下webWorker在前端生成Excel的场景下的使用

在主进程页面中,创建一个按钮去触发事件,接收到worker线程中传递的数据将其下载下来

vue 复制代码
<script setup>
// 这样的方式也可,但importScripts会报错,原因未知
// import MyWorker from "./utils/uploadExcel.js?worker"
// const worker = new MyWorker()
const worker = new Worker(new URL('./utils/uploadExcel.js?raw', import.meta.url))
// 监听消息
worker.onmessage = ({ data }) => {
  const a = document.createElement("a");
  a.download = `${new Date().toLocaleTimeString()}.xlsx`;
  a.href = URL.createObjectURL(new Blob([data], { type: "application/octet-stream" }));
  a.click();
}
const getExcel = () => {
  worker.postMessage("start")
}
</script>
<template>
  <div>
    <button type="button" @click="getExcel">点击下载Excel</button>
  </div>
</template>

在worker进程中

javascript 复制代码
self.importScripts('https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.15.3/xlsx.core.min.js');
const getHq = () => {
  return new Promise((res) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", "http://localhost:3002/list", true);
    xhr.onload = () => {
      if (xhr.status === 200) {
        const responseData = xhr.responseText;
        res(responseData)
      } else {
        console.error("请求失败,状态码:" + xhr.status);
      }
    };
    xhr.send();
  })
}
onmessage = function (event) {
  const { data } = event
  if (data === "start") {
    let startTime = new Date();
    getHq().then(res => {
      console.log("开始整理数据-"+startTime);
      res= JSON.parse(res);
      const ws = XLSX.utils.aoa_to_sheet(res.data, { dense: true });
      const wb = XLSX.utils.book_new();
      XLSX.utils.book_append_sheet(wb, ws);
      postMessage(XLSX.write(wb, {type: 'array', bookType: 'xlsx', bookSST: true, compression: true}));
      let endTime = new Date()
      console.log("结束正在将数据发送给主线程-"+endTime)
      console.log(`传递总耗时间${Math.floor((endTime - startTime )/ 1000)}`);
    });
  }
}

在网络上随便找的xlsx.js文件路径通过importScripts放入worker线程中加载,在webWorker中也可以发起请求,在上面的代码中通过原生的XML进行请求后端数据,当然这里也可以使用fetch。接收到数据将其发送给主线程。

javascript 复制代码
// 引入 Express.js 模块
const express = require('express');
// 创建 Express 应用程序
const app = express();
// 创建一个路由,响应根路径的 GET 请求
app.get('/list', (req, res) => {
    const ListData = new Array(100000).fill(new Array(20).fill("这是一段文本"));
    res.json({data:ListData});
});
// 启动服务器并监听端口
const port = 3001;
app.listen(port, () => {
    console.log(`Express app listening on port ${port}`);
});

启动一个express,模拟后端发送数据。当然你也可以通过主线程将数据传递进worker线程用来填充Excel的数据,这样一个简单的Excel下载就完成了。

yaml 复制代码
开始整理数据-Wed Nov 08 2023 18:07:36 GMT+0800 (香港标准时间)
结束正在将数据发送给主线程-Wed Nov 08 2023 18:07:43 GMT+0800 (香港标准时间)
传递总耗时间7

结束语

webWorker优势

独立运行,沙箱一样的隔离机制,异步并行计算

webWorker劣势

兼容性差,没有办法访问dom,编码成本高,通过拷贝的方式传输数据(js允许主线程向worker线程直接转移二进制数据,这个除外)

参考资料

Web Worker 使用教程 - 阮一峰的网络日志
使用 Web Workers - Web API 接口参考 | MDN

相关推荐
然我8 分钟前
react-router-dom 完全指南:从零实现动态路由与嵌套布局
前端·react.js·面试
一_个前端16 分钟前
Vite项目中SVG同步转换成Image对象
前端
202617 分钟前
12. npm version方法总结
前端·javascript·vue.js
用户876128290737418 分钟前
mapboxgl中对popup弹窗添加事件
前端·vue.js
帅夫帅夫19 分钟前
JavaScript继承探秘:从原型链到ES6 Class
前端·javascript
a别念m19 分钟前
HTML5 离线存储
前端·html·html5
goldenocean1 小时前
React之旅-06 Ref
前端·react.js·前端框架
子林super1 小时前
【非标】es屏蔽中心扩容协调节点
前端
前端拿破轮1 小时前
刷了这么久LeetCode了,挑战一道hard。。。
前端·javascript·面试
代码小学僧1 小时前
「双端 + 响应式」企业官网开发经验分享
前端·css·响应式设计