在前端处理导出excel文件时,当数据量过多时,页面阻塞假死,因此了解了多线程机制,想来解决此问题。(正确做法应该是让后端处理导出,前端直接给个链接点击请求下载)
web Worker
浏览器中 JS 都是单线程工作,当在前端执行一些耗时的工作时,页面后续渲染等步骤都会等待,就会导致一些页面的卡顿假死,影响用户体验。
webworker 的出现,就是给js创建多线程的环境。主线程创建worker线程,可以把计算密集型或高延迟的任务交给worker线程执行,主线程运行的同时worker线程也在运行,相互不干扰,主线程负责UI交互,这样主线程就不会被阻塞。
使用
创建多线程
const worker = new Worker(path, options);
主线程js文件
// 创建多线程
const worker = new Worker(`assets/download-excel.worker.js`);
// 通过postMessage来建立主副线程的沟通,从而进行数据传递
worker.postMessage(data);
// 通过onmessage接收从webWorker传来的数据
worker.onmessage = ({ data }) => {
if (data) {
// worker耗费资源,结束后需要关闭
worker.terminate();
worker = undefined;
}
};
worker.js文件
/// <reference lib="webworker" />
// worker里面引入外部js文件只能用importScripts
importScripts('exceljs');
// 监听主线程,并接收传来的数据
addEventListener('message', ({ data }) => {
if (data) {
// 需要在worker里执行的耗时操作
postMessage('结束');
}
});
踩坑
1.创建worker文件时,引入js文件路径有问题,导致报错
这是因为worker文件路径有两个限制:
1.分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
2.worker 不能读取本地的文件(不能打开本机的文件系统file://),它所加载的脚本必须是网络资源文件。
在框架中运用时,一般可能会放在主线程js文件同级目录下,用相对路径,会导致在本地开发时,引入路径不同源,这个问题说在上线时就不会遇到,但是我没进行验证。
处理方法:
- 将worker文件放置在assets文件夹下面,直接获取地址拼接
const worker = new Worker(window.location.href + `assets/download-excel.worker.js`);
- 将js代码字符串化,运用new Blog转换js代码,生成一个url地址
const blob = new Blob([`
addEventListener('message', ({data}) => {
if (data) {
postMessage('结束');
}
});`
], {type: 'text/javascript'});
const url = window.URL.createObjectURL(blob);
worker = new Worker(url);