摘要:背景前一陣子開發(fā)的項(xiàng)目導(dǎo)入由于自己的代碼問題引起了個(gè)性能問題一個(gè)的文件轉(zhuǎn)換成數(shù)據(jù)大概要耗時(shí)雖然后面發(fā)現(xiàn)是某個(gè)使用頻率非常高的函數(shù)內(nèi)部用了構(gòu)造函數(shù)造成的所以這里順便提醒一下如果你很在乎幾毫秒的差距的話建議謹(jǐn)慎使用哈但是在優(yōu)化的過程中一度懷疑是
背景
前一陣子開發(fā)的項(xiàng)目 pptx 導(dǎo)入, 由于自己的代碼問題,引起了個(gè)性能問題,一個(gè) 40p 的 pptx 文件,轉(zhuǎn)換成 json 數(shù)據(jù),大概要耗時(shí) 60s+ ,雖然后面發(fā)現(xiàn)是某個(gè)使用頻率非常高的函數(shù)內(nèi)部,用了 new Function 構(gòu)造函數(shù) 造成的(所以這里順便提醒一下,如果你很在乎幾毫秒的差距的話,建議謹(jǐn)慎使用哈),但是在優(yōu)化的過程中,一度懷疑是性能達(dá)到了瓶頸,所以嘗試了使用 web worker 去優(yōu)化,由于是文件,一般內(nèi)容都比較大,發(fā)現(xiàn) web worker 在傳值這塊占用了大部分的時(shí)間,所以想開這篇來(lái)詳細(xì)聊聊.
兩種傳值方式關(guān)于 web worker 的基本用于以及傳值方式,網(wǎng)上以及有一大堆介紹了,這里就不贅述了,這里我們重點(diǎn)來(lái)看一下同一個(gè)文件用兩種方式來(lái)傳值,會(huì)有多大的差別,這邊隨意從電腦里面找了一個(gè) 96MB 的 PSD 文件來(lái)測(cè)試.
主線程
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("計(jì)算時(shí)間"); worker.postMessage(buf); worker.onmessage = e => { console.timeEnd("計(jì)算時(shí)間"); } })
worker(子)線程, 這里為了避免不必要的因素干擾,worker 線程里面什么也不做,在收到消息后,直接 post 一個(gè)消息回去
self.onmessage = e => { postMessage(0); }
這邊我直接用 FileReader 的 readAsArrayBuffer,讀出來(lái)是一個(gè)長(zhǎng)度為 96,138,230 的字符串,長(zhǎng)度大概 0.96 億, 耗時(shí)大概 70ms 左右(同一個(gè)臺(tái)電腦取 10 次平均值,下同)
我們稍微改一下上面主線程的代碼,改用 轉(zhuǎn)移數(shù)據(jù) 的方式
- worker.postMessage(buf); + worker.postMessage(buf, [buf]);
同樣的數(shù)據(jù), 耗時(shí)大概 17ms 左右,這 17ms 好像是個(gè)固定值,我嘗試換了個(gè) 800MB+ 的文件和一個(gè)里面啥都沒有的空文本文件,大概都是這個(gè)時(shí)間.
不同的數(shù)據(jù)類型,用值傳遞的耗時(shí)也是不一樣的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("計(jì)算時(shí)間"); worker.postMessage(str); worker.onmessage = e => { console.timeEnd("計(jì)算時(shí)間"); } })
這里我們改用 FileReader 的 readAsText,讀出來(lái)是一個(gè)長(zhǎng)度為 95,855,954 的字符串,長(zhǎng)度大概 0.95 億, 耗時(shí)大概 118ms 左右,同樣我換了上面那個(gè)里面啥都沒有的空文本文件,耗時(shí)也是 17ms 左右.
那我們?cè)囋囉?readAsDataURL 看看讀出來(lái)的數(shù)據(jù)要多久
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("計(jì)算時(shí)間"); worker.postMessage(str); worker.onmessage = e => { console.timeEnd("計(jì)算時(shí)間"); } })
讀出來(lái)是一個(gè)長(zhǎng)度為 128,184,345 的字符串,長(zhǎng)度大概 1,28 億, 耗時(shí)大概 85ms 左右(雖然字符串長(zhǎng)度更長(zhǎng),但是耗時(shí)卻更短)
以上耗時(shí),均為主線成向 worker 線程單向傳遞數(shù)據(jù)的耗時(shí).結(jié)論
轉(zhuǎn)移數(shù)據(jù)幾乎是零開銷(因?yàn)楹蛡鬟f空字符串的耗時(shí)是差不多的).
值傳遞的話,不同的數(shù)據(jù)類型,耗時(shí)也有差別,ArrayBuffer < base64 < 普通字符串.
postMessage 傳遞消息,除了發(fā)送數(shù)據(jù)的耗時(shí)外,還有其他開銷(就是上面的 17ms). 當(dāng)然每臺(tái)電腦性能不一樣,耗時(shí)也是不一樣的,不過按比例來(lái)看,這個(gè)占比還挺大的.
關(guān)于轉(zhuǎn)移的缺點(diǎn), 網(wǎng)上也是有很多的, 這里也就不啰嗦了, 總結(jié)一句就是數(shù)據(jù)無(wú)法同時(shí)在2個(gè)線程上使用.
另外個(gè)人覺得如果是普通的數(shù)據(jù),為了轉(zhuǎn)移而去轉(zhuǎn)換成 Transferable objects 的話, 大部分情況下是劃不來(lái)的, 因?yàn)槟阈枰诨ㄔ诰幋a解碼上的時(shí)間,會(huì)比直接傳遞花的時(shí)間多.
另外, 如果你是要用子線程處理圖片的話, ImageBitmap 格式 配合最近新鮮出爐的 OffscreenCanvas 也許是不錯(cuò)的選擇.前提是你不需要考慮兼容性問題.
最后是廣告時(shí)間我們40人的前端團(tuán)隊(duì)常年招兵買馬中,在廈門的和想來(lái)廈門的童鞋們,不要吝惜你的簡(jiǎn)歷,使勁砸過來(lái) 郵箱:[email protected], 期待你一起來(lái)稿事
原文地址 https://github.com/noahlam/ar...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101518.html
摘要:可以將耗時(shí)任務(wù)拆解出去,降低主線程的壓力,避免主線程無(wú)響應(yīng)。主線程接收發(fā)消息每個(gè)實(shí)例通過接收消息,通過發(fā)送消息。收發(fā)主線程消息和主線程代碼類似,在代碼中,也是接收消息,這個(gè)消息來(lái)自主線程或者其它。 1 引言 本周精讀的文章是 speedy-introduction-to-web-workers,是一篇 Web Workers 快速入門的文章,借精讀這篇文章的機(jī)會(huì),談?wù)剬?duì) Web Wor...
摘要:組件之間的通訊分為三種父給子傳子給父?jìng)餍值芙M件之間的通訊父組件給子組件傳值子組件嵌套在父組件內(nèi)部,父組件給子組件傳遞一個(gè)標(biāo)識(shí),在子組件內(nèi)部用接收,子組件在模板里可以通過的形式進(jìn)行使用。 組件之間的通訊分為三種 父給子傳 子給父?jìng)?兄弟組件之間的通訊 1 父組件給子組件傳值 子組件嵌套在父組件內(nèi)部,父組件給子組件傳遞一個(gè)標(biāo)識(shí),在子組件內(nèi)部用props接收,子組件在模板里可以通過{{}}的...
摘要:組件之間的通訊分為三種父給子傳子給父?jìng)餍值芙M件之間的通訊父組件給子組件傳值子組件嵌套在父組件內(nèi)部,父組件給子組件傳遞一個(gè)標(biāo)識(shí),在子組件內(nèi)部用接收,子組件在模板里可以通過的形式進(jìn)行使用。 組件之間的通訊分為三種 父給子傳 子給父?jìng)?兄弟組件之間的通訊 1 父組件給子組件傳值 子組件嵌套在父組件內(nèi)部,父組件給子組件傳遞一個(gè)標(biāo)識(shí),在子組件內(nèi)部用props接收,子組件在模板里可以通過{{}}的...
摘要:組件之間的通訊分為三種父給子傳子給父?jìng)餍值芙M件之間的通訊父組件給子組件傳值子組件嵌套在父組件內(nèi)部,父組件給子組件傳遞一個(gè)標(biāo)識(shí),在子組件內(nèi)部用接收,子組件在模板里可以通過的形式進(jìn)行使用。 組件之間的通訊分為三種 父給子傳 子給父?jìng)?兄弟組件之間的通訊 1 父組件給子組件傳值 子組件嵌套在父組件內(nèi)部,父組件給子組件傳遞一個(gè)標(biāo)識(shí),在子組件內(nèi)部用props接收,子組件在模板里可以通過{{}}的...
閱讀 2676·2021-11-25 09:43
閱讀 2484·2021-09-22 15:29
閱讀 1000·2021-09-22 15:17
閱讀 3641·2021-09-03 10:36
閱讀 2236·2019-08-30 13:54
閱讀 1757·2019-08-30 11:23
閱讀 1171·2019-08-29 16:58
閱讀 1302·2019-08-29 16:14