背景
前一阵子开辟的项目 pptx 导入
, 由于本身的代码题目,引起了个机能题目,一个 40p 的 pptx 文件,转换成 json 数据,大提要耗时 60s+ ,虽然背面发明是某个运用频次异常高的函数内部,用了 new Function 组织函数
形成的(所以这里趁便提示一下,假如你很在意几毫秒的差异的话,发起郑重运用哈),然则在优化的过程当中,一度怀疑是机能达到了瓶颈,所以尝试了运用 web worker 去优化,由于是文件,平常内容都比较大,发明 web worker 在传值这块占用了大部分的时候,所以想开这篇来细致聊聊.
两种传值体式格局
关于 web worker 的基础用于以及传值体式格局,网上以及有一大堆引见了,这里就不赘述了,这里我们重点来看一下同一个文件用两种体式格局来传值,会有多大的差异,这边随便从电脑内里找了一个 96MB 的 PSD 文件来测试.
主线程
fetch('./case.psd').then(file => {
return file.blob();
})
.then(blob => {
return new Promise(resolve => {
let fileReader = new FileReader();
fileReader.onload = e => {
resolve(e.target.result);
}
fileReader.readAsArrayBuffer(blob);
})
})
.then(buf => {
let worker = new Worker('1.js');
console.time('盘算时候');
worker.postMessage(buf);
worker.onmessage = e => {
console.timeEnd('盘算时候');
}
})
worker(子)线程, 这里为了防止不必要的要素滋扰,worker 线程内里什么也不做,在收到音讯后,直接 post 一个音讯归去
self.onmessage = e => {
postMessage(0);
}
这边我直接用 FileReader 的 readAsArrayBuffer,读出来是一个长度为 96,138,230 的字符串,长度也许 0.96 亿, 耗时也许 70ms 摆布(同一个台电脑取 10 次平均值,下同)
我们轻微改一下上面主线程的代码,改用 转移数据
的体式格局
- worker.postMessage(buf);
+ worker.postMessage(buf, [buf]);
一样的数据, 耗时也许 17ms 摆布,这 17ms 好像是个固定值,我尝试换了个 800MB+ 的文件和一个内里啥都没有的空文本文件,也许都是这个时候.
差别的数据类型,用值通报的耗时也是不一样的
fetch('./case.psd').then(file => {
return file.blob();
})
.then(blob => {
return new Promise(resolve => {
let fileReader = new FileReader();
fileReader.onload = e => {
resolve(e.target.result);
}
fileReader.readAsText(blob);
})
})
.then(str => {
console.log(str.length);
let worker = new Worker('1.js');
console.time('盘算时候');
worker.postMessage(str);
worker.onmessage = e => {
console.timeEnd('盘算时候');
}
})
这里我们改用 FileReader 的 readAsText,读出来是一个长度为 95,855,954 的字符串,长度也许 0.95 亿, 耗时也许 118ms 摆布,一样我换了上面谁人内里啥都没有的空文本文件,耗时也是 17ms 摆布.
那我们试试用 readAsDataURL 看看读出来的数据要多久
fetch('./case.psd').then(file => {
return file.blob();
})
.then(blob => {
return new Promise(resolve => {
let fileReader = new FileReader();
fileReader.onload = e => {
resolve(e.target.result);
}
fileReader.readAsDataURL(blob);
})
})
.then(str => {
console.log(str.length);
let worker = new Worker('1.js');
console.time('盘算时候');
worker.postMessage(str);
worker.onmessage = e => {
console.timeEnd('盘算时候');
}
})
读出来是一个长度为 128,184,345 的字符串,长度也许 1,28 亿, 耗时也许 85ms 摆布(虽然字符串长度更长,然则耗时却更短)
以上耗时,均为主线成向 worker 线程单向通报数据的耗时.
结论
- 转移数据几乎是零开支(由于和通报空字符串的耗时是差不多的).
- 值通报的话,差别的数据类型,耗时也有差异,ArrayBuffer < base64 < 一般字符串.
- postMessage 通报音讯,除了发送数据的耗时外,另有其他开支(就是上面的 17ms). 固然每台电脑机能不一样,耗时也是不一样的,不过按比例来看,这个占比还挺大的.
关于转移的瑕玷, 网上也是有许多的, 这里也就不烦琐了, 总结一句就是数据没法同时在2个线程上运用.
别的个人以为假如是一般的数据,为了转移而去转换成 Transferable objects
的话, 大部分情况下是划不来的, 由于你需要在花在编码解码上的时候,会比直接通报花的时候多.
别的, 假如你是要用子线程处置惩罚图片的话, ImageBitmap
花样 合营近来新鲜出炉的 OffscreenCanvas
也许是不错的挑选.条件是你不需要斟酌兼容性题目.
末了是广告时候
我们40人的前端团队终年招兵买马中,在厦门的和想来厦门的童鞋们,不要怜惜你的简历,用力砸过来 邮箱:nuoya@gaoding.com
, 期待你一起来稿事