webwoker是什么?
webwoker是在es5提出的,是在页面主线程外单独开一条线程用于处理复杂业务,防止主线程阻塞的技术。
首先由于浏览器是单线程(浏览器单线程的原因是为了防止出现资源竞争的情况出现,所以在设计初期采用了单线程模式的原因。

但是单线程设计导致用户在访问浏览器过程中出现长时间任务,页面整体卡顿,导致用户体验差情况出现。

在es5之前当出现长任务,通常通过将长任务拆分成多个段任务去处理,或者通过其他的数据传输方式传输给前端。 es5以后我们可以通过webworker重新创建一条新的线程去处理相关任务。

场景:
今年7月做自己小项目时候出现,当后端返回百万级数据的时候前端接受数据,然后转换成相关文档耗时太长,导致整体页面体验感差,因此当时考虑在下载文件的过程中使用webworker来处理http请求的数据。
需求:
客户每月上传百万条excle数据,然后在下一个月需要将这些数据根据客户进行分批导出。
刚开始的解决方案是,后端查询上一个月所有数据,然后根据客户id进行聚合后将所有数据返回给前端,然后前端将拿到的数据进行拆分,按个进行导出。经过后期测试发现前端用户触发一次下载后一个http请求的时长有时候长达1min左右。
改进方案,先通过请求获取上一个月用户快递数量,然后在根据用户分批请求下载excle数据,最后使用webworker去处理这些请求,这样及时有某一些用户数据体量过大,也会在webworker中去处理,不会导致主线程阻塞。
部分实现代码:
//vue.config.js中webworker配置
chainWebpack: config => {
// set worker-loader
config.module
.rule('worker')
.test(/.worker.js$/)
.use('worker-loader')
.loader('worker-loader')
.end();
},
// worker.js使用webworker
import axios from "axios";
self.onmessage = (params) => {
console.log(88833, params.data);
axios.defaults.headers.Authorization = params.data.token;
const paramsTemp = {
type: "all",
all: true,
name: params.data.name,
fileName: params.data.fileName,
timeStamp: params.data.timeStamp,
}
if (params.data.startTime) {
paramsTemp.startTime = params.data.startTime;
}
if (params.data.endTime) {
paramsTemp.endTime = params.data.endTime;
}
const length = params.data.data.length
let startNum = 0;
const getDataFun = function(num, length) {
paramsTemp.userId = params.data.data[num]._id
axios.get(params.data.url, {
params: paramsTemp,
}).then(res => {
console.log('总共:', length)
console.log('当前:', num)
self.postMessage({
type: 'continue',
data: res.data
})
num++;
if(num === length) {
getAllData()
} else {
getDataFun(num, length)
}
})
}
getDataFun(startNum, length)
const getAllData = function() {
axios.get(params.data.url, {
params: {
type: 'countAll',
timeStamp: params.data.timeStamp,
},
}).then(res => {
self.postMessage({
type: 'continue',
data: res.data
})
self.postMessage({ type: 'close' })
})
}
}
// vue组件中使用worke.js并且进行数据通讯
import Worker from './worker.js';
this.worker = new Worker()
const paramsTemp = {
data: res.data,
name: this.inputData,
fileName: this.fileName,
token: 'Bearer ' + localStorage.getItem('auth_token'),
url: 'http://localhost:7001/api/download',
timeStamp
}
if (this.value && this.value.length) {
paramsTemp.startTime = this.value[0];
paramsTemp.endTime = this.value[1];
}
this.worker.postMessage(paramsTemp)
this.worker.addEventListener('message', (e) => {
console.log('主线程监听到子线程发送的消息事件', e.data)
if (e.data.type !== 'close') {
const dataAll = e.data.data;
dataAll.forEach((elt) => {
let buf;
if (typeof ArrayBuffer !== "undefined") {
buf = new ArrayBuffer(elt.data.length);
const view = new Uint8Array(buf);
for (let i = 0; i !== elt.data.length; ++i) {
view[i] = elt.data.charCodeAt(i) & 0xff;
}
} else {
buf = new Array(elt.data.length);
for (let i = 0; i !== elt.data.length; ++i) {
buf[i] = elt.data.charCodeAt(i) & 0xff;
}
}
const blob = new Blob([buf], { type: "application/octet-stream" });
FileSaver.saveAs(blob, elt.name + ".xlsx");
});
} else {
this.worker.terminate()
this.loadingDown = false;
this.loading = false;
}
})
}

浙公网安备 33010602011771号