前一陣子開發的項目 pptx 導入
, 因爲本身的代碼問題,引發了個性能問題,一個 40p 的 pptx 文件,轉換成 json 數據, 大概要耗時 60s+ ,雖而後面發現是某個使用頻率很是高的函數內部,用了 new Function 構造函數
形成的 (因此這裏順便提醒一下,若是你很在意幾毫秒的差距的話,建議謹慎使用哈), 可是在優化的過程當中,一度懷疑是性能達到了瓶頸,因此嘗試了使用 web worker 去優化,因爲是文件,通常內容都比較大, 發現 web worker 在傳值這塊佔用了大部分的時間,因此想開這篇來詳細聊聊.javascript
關於 web worker 的基本用於以及傳值方式,網上以及有一大堆介紹了,這裏就不贅述了, 這裏咱們重點來看一下同一個文件用兩種方式來傳值,會有多大的差異,這邊隨意從電腦裏面找了一個 96MB 的 PSD 文件來測試.前端
主線程java
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 一個消息回去git
self.onmessage = e => {
postMessage(0);
}
複製代碼
這邊我直接用 FileReader 的 readAsArrayBuffer,讀出來是一個長度爲 96,138,230 的字符串, 長度大概 0.96 億, 耗時大概 70ms 左右(同一個臺電腦取 10 次平均值,下同)github
咱們稍微改一下上面主線程的代碼,改用 轉移數據
的方式web
- worker.postMessage(buf);
+ worker.postMessage(buf, [buf]);
複製代碼
一樣的數據, 耗時大概 17ms 左右,這 17ms 好像是個固定值,我嘗試換了個 800MB+ 的文件和一個裏面啥都沒有的空文本文件, 大概都是這個時間.json
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 左右.bash
那咱們試試用 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 左右(雖然字符串長度更長,可是耗時卻更短)post
以上耗時,均爲主線成向 worker 線程單向傳遞數據的耗時.
關於轉移的缺點, 網上也是有不少的, 這裏也就不囉嗦了, 總結一句就是數據沒法同時在2個線程上使用.
另外我的以爲若是是普通的數據,爲了轉移而去轉換成 Transferable objects
的話, 大部分狀況下是划不來的, 由於你須要在花在編碼解碼上的時間,會比直接傳遞花的時間多.
另外, 若是你是要用子線程處理圖片的話, ImageBitmap
格式 配合最近新鮮出爐的 OffscreenCanvas
也許是不錯的選擇.前提是你不須要考慮兼容性問題.
咱們40人的前端團隊常年招兵買馬中,在廈門的和想來廈門的童鞋們,不要吝惜你的簡歷,使勁砸過來 郵箱:nuoya@gaoding.com
, 期待你一塊兒來稿事