js是单线程的 一些计算量大的数据放在前端一般情况下会造成两种情况
- 页面卡死
- 在计算的过程中用户操作页面是无响应的
Worker
Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。
Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭
Worker.postMessage()
Worker 接口的 postMessage() 方法可以向 worker 发送消息。第一个参数是要发送到 worker 的数据。该数据可以是任何可以被结构化克隆算法处理的 JavaScript 对象。
Worker 的 postMessage() 方法委托给 MessagePort 的 postMessage() (en-US) 方法,该方法会在对应的用于接收 MessagePort 的事件循环中添加一个任务。
Worker.terminate()
Worker 接口中的 terminate() 方法用于立即终止 Worker 的行为。本方法并不会等待 worker 去完成它剩余的操作;worker 将会被立刻停止。
Worker:message 事件
当 worker 的父级接收到来自其 worker 的消息时(也就是说,当 worker 通过 DedicatedWorkerGlobalScope.postMessage() (en-US) 发送消息时),会在 Worker 对象上触发 message 事件。
此事件不能取消,也不会冒泡。
Demo
<script setup>
import { ref } from "vue";
import { xlsx } from "./../utils/xlsx.js";
const val = ref("");
const listHander = ref({
id: "学号",
name: "姓名",
age: "年龄",
classes: "学院",
});
const jsonData = ref([]);
for (let i = 0; i < 500000; i++) {
jsonData.value.push({
id: i,
name: "小智" + i,
age: i,
classes: "商学院",
});
}
const exportHandler = () => {
console.log("导出");
xlsx(jsonData.value, listHander.value, "study");
};
</script>
<template>
<input v-model="val" />
<button @click="exportHandler">导出</button>
</template>
<style scoped></style>
- 循环生成50万条数据
- 定义了一个导出事件 exportHandler
虽然效果已达预期 可以正确导出文件 但是点击 导出按钮 在导出文件的过程中 输入框乃至整个页面 操作是无响应的
接下来使用worker优化
const xlsxWorker = new Worker("http://localhost:5173/exportXlsx.js");
xlsxWorker.onmessage = (e) => {
const workerBook = e.data
writeFile(workerBook,"ttt.xlsx")
xlsxWorker.terminate()
};
const exportHandler = () => {
xlsxWorker.postMessage("开始下载")
};
exportXlsx.js
importScripts('./xlsx.js')
const jsonData = [];
for (let i = 0; i < 1000000; i++) {
jsonData.push({
id: i,
name: "小智" + i,
age: i,
classes: "商学院",
});
}
const listHander = {
id: "学号",
name: "姓名",
age: "年龄",
classes: "学院",
};
console.log(XLSX);
self.onmessage = function () {
const sheet = XLSX.utils.json_to_sheet(jsonData);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, sheet, 'sheet1');
self.postMessage(workbook)
}
XLSX对象打印
整体思路
- new Worker()开启一个线程 计算类交给线程去做
- 用户触发后 使用postMessage向线程传递信息
- 线程通过onmessage监听到并计算后 将结果通过postMessage向主线程传递
- 主线程通过onmessage接收到后进行操作