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