前一陣子開發的項目 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 左右.函數
那咱們試試用 readAsDataURL 看看讀出來的數據要多久post
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 線程單向傳遞數據的耗時.
關於轉移的缺點, 網上也是有不少的, 這裏也就不囉嗦了, 總結一句就是數據沒法同時在2個線程上使用.
另外我的以爲若是是普通的數據,爲了轉移而去轉換成 Transferable objects
的話, 大部分狀況下是划不來的, 由於你須要在花在編碼解碼上的時間,會比直接傳遞花的時間多.
另外, 若是你是要用子線程處理圖片的話, ImageBitmap
格式 配合最近新鮮出爐的 OffscreenCanvas
也許是不錯的選擇.前提是你不須要考慮兼容性問題.
咱們40人的前端團隊常年招兵買馬中,在廈門的和想來廈門的童鞋們,不要吝惜你的簡歷,使勁砸過來 郵箱:nuoya@gaoding.com
, 期待你一塊兒來稿事