<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【W(wǎng)eb技術(shù)】972- 純前端生成海報(bào)實(shí)踐及其性能調(diào)優(yōu)

          共 3186字,需瀏覽 7分鐘

           ·

          2021-06-08 22:30

          1 需求背景

          接到了一個緊急需求,需要根據(jù) Excel 表格中學(xué)生的信息以及考試成績生成相應(yīng)的海報(bào)。

          Excel 數(shù)據(jù)和需要生成的海報(bào)的樣式如下:

          Excel 數(shù)據(jù)

          海報(bào)樣式

          由于需求緊急,沒有時間拉上后端同學(xué),所以 Excel 表格的數(shù)據(jù)解析和海報(bào)生成功能都需要由前端開發(fā)。

          以下幾個技術(shù)點(diǎn)需要關(guān)注:

          1. Excel 可以通過 sheetjs來處理,通過在 XLSX.utils.sheet_to_json 將 Excel 中的數(shù)據(jù)轉(zhuǎn)化為 JSON 格式數(shù)據(jù)。
          2. 海報(bào)圖片的生成可以先通過 html2canvas 將 HTML 轉(zhuǎn)化成 canvas ,然后通過 canvas.toBlob 獲得。
          3. 最終通過JSZip 將圖片打包進(jìn)壓縮包中。
          4. 這里表單可配置項(xiàng)會比較多,因此我們需要一個配置導(dǎo)入導(dǎo)出功能,這里我們可以使用 FileReader 來實(shí)現(xiàn)表單配置導(dǎo)入,FileReader.readAsTextapi 能夠讀取文本的內(nèi)容,更多用法可以參考 MDN FileReader。

          在此基礎(chǔ)上,確定此需求的總體開發(fā)思路:

          1. 首先我們需要一個表單,獲得海報(bào)可變文案的配置信息,例如不同題目考試成績所對應(yīng)的評語。

          2. 遍歷 Excel 中的每一條數(shù)據(jù),根據(jù)每一條數(shù)據(jù)和表單的配置信息生成對應(yīng)海報(bào)的 HTML 模板。

          3. 根據(jù) HTML 模板生成圖片,并將圖片數(shù)據(jù)保存進(jìn)壓縮包的對象中。

          4. Excel 中的數(shù)據(jù)處理完后,下載壓縮包,結(jié)束流程。

          按照這個流程將功能開發(fā)完畢后,我在自己的機(jī)器上使用 100 條數(shù)據(jù)量的 Excel 表格進(jìn)行測試,可以成功生成對應(yīng)的壓縮包,壓縮包中的圖片也沒有問題,給運(yùn)營同學(xué)演示后,她也表示很滿意。

          2 測試問題

          但是當(dāng)天晚上運(yùn)營同學(xué)在自己的電腦測試這個工具時,悲劇發(fā)生了……

          網(wǎng)頁崩潰

          在運(yùn)營同學(xué)的電腦上,使用 15 條 Excel 表格數(shù)據(jù)生成海報(bào)時表現(xiàn)正常,當(dāng)增加到 20 條 Excel 表格數(shù)據(jù)時,出現(xiàn)了網(wǎng)頁崩潰的情況,提示 Out Of Memory。

          3 分析問題

          3.1 js內(nèi)存問題

          現(xiàn)在讓我們來一起分析一下,在哪里出現(xiàn)了問題?

          分析發(fā)現(xiàn),最有可能出現(xiàn)問題的地方是步驟 3——最終通過JSZip將圖片打包進(jìn)壓縮包中。

          壓縮包對象所占用的內(nèi)存在 Excel 表格數(shù)據(jù)處理完成并下載之前是不會被釋放的,會一直增長。

          所以我們有了一個簡單的方案——分包。每處理 10 條數(shù)據(jù)就下載一次壓縮包,將 JSZip (壓縮包對象)所占用的內(nèi)存釋放。

          但是事情真的有這么簡單嗎?20 張圖片的數(shù)據(jù)以每張 1MB 的大小計(jì)算也才 20MB,怎么可能會導(dǎo)致網(wǎng)頁崩潰呢?

          憑空猜測沒有作用,我們使用瀏覽器的 Performance 工具進(jìn)行分析。

          網(wǎng)頁內(nèi)存增長情況 1

          可以看到 JS Heap 在每處理一條 Excel 表格數(shù)據(jù)后都會增長,沒有得到釋放,這里沒有得到釋放的內(nèi)存占用是上文分析的 JSZip 導(dǎo)致的嗎?

          繼續(xù)使用瀏覽器的 Memory 工具進(jìn)行分析。

          網(wǎng)頁內(nèi)存快照

          可以看到,內(nèi)存占用確實(shí)是一直在漲,沒有得到釋放,放大其中的一項(xiàng)。

          網(wǎng)頁內(nèi)存快照詳細(xì)信息

          什么?竟然是 system.context ?作為一個前端開發(fā),相信你看到這個詞腦子里第一個冒出的念頭應(yīng)該就是上下文。檢查代碼,發(fā)現(xiàn)代碼中使用了遞歸,所以造成了大量內(nèi)存的使用,這里就不展示問題代碼了。

          將代碼修改為循環(huán)語句后,再進(jìn)行測試。

          網(wǎng)頁內(nèi)存增長情況 2

          可以看到內(nèi)存的增長已經(jīng)正常。讓運(yùn)營同學(xué)再次進(jìn)行測試。

          3.2 DOM 問題

          問題就這樣被解決了嗎?

          信心滿滿的找到運(yùn)營同學(xué)進(jìn)行測試,結(jié)果出乎意料,運(yùn)營同學(xué)的電腦依然處理不了 40 條以上的 Excel 表格數(shù)據(jù),而且在測試中還出現(xiàn)了一個問題,數(shù)據(jù)處理到某個階段時,會卡住很久!

          為了解決問題,我們繼續(xù)進(jìn)行分析。

          排查內(nèi)存溢出的問題可以從兩方面入手——JS 和 DOM。既然 JS 的問題我們已經(jīng)解決,那就看看 DOM。

          整體流程中,對 DOM 進(jìn)行操作的地方有兩點(diǎn):

          1. 根據(jù) Excel 表格數(shù)據(jù)生成對應(yīng)海報(bào)的 HTML 模板。

          2. 根據(jù) HTML 模板生成圖片。

          第一點(diǎn)應(yīng)該不存在內(nèi)存溢出問題,因?yàn)槲覀兗葲]有在 HTML 模版上添加事件,在處理下一條數(shù)據(jù)時也是直接覆蓋上一次生成的HTML 模板,不會導(dǎo)致 DOM 節(jié)點(diǎn)不停增加。

          繼續(xù)分析第二點(diǎn),我使用了第三方庫 html2canvas ,由對應(yīng)的節(jié)點(diǎn)生成 canvas 對象,之后由 canvas 對象生成圖片的二進(jìn)制數(shù)據(jù)。

          根據(jù) html2canvas 文檔的指引,設(shè)置 removeContainer 屬性保留其生成 canvas 對象時所克隆的 DOM 元素并查看。

          DOM結(jié)構(gòu)

          結(jié)果出乎意料,html2canvas 完整的克隆了我們的 DOM 結(jié)構(gòu),除目標(biāo)節(jié)點(diǎn)外還克隆了 React 的根結(jié)點(diǎn),script 標(biāo)簽,link 標(biāo)簽。

          此時,數(shù)據(jù)處理慢以及在處理某條數(shù)據(jù)時卡慢的問題就清楚了,由于 html2canvas 完整的克隆了我們的 DOM 結(jié)構(gòu),不僅復(fù)制了很多沒用的節(jié)點(diǎn),而且由于克隆了 script 標(biāo)簽,link 標(biāo)簽,還會發(fā)起網(wǎng)絡(luò)請求下載相關(guān)的資源。

          我們需要把進(jìn)行操作的節(jié)點(diǎn)插入在 body 標(biāo)簽下,根據(jù)文檔指引,可以使用 html2canvas 提供的ignoreElements屬性解決以上問題:

          const canvas = await html2canvas(root, {
            imageTimeout10000,
            ignoreElements(ele) => ele.id === 'root' || ele.tagName.toUpperCase() === 'IFRAME' || ele.tagName.toUpperCase() === 'SCRIPT' || ele.tagName.toUpperCase() === 'LINK',
          });

          通過以上代碼,我們將無用的節(jié)點(diǎn)和會造成網(wǎng)絡(luò)請求的標(biāo)簽進(jìn)行了過濾。

          優(yōu)化過后,再讓運(yùn)營同學(xué)進(jìn)行測試,這時處理一千條數(shù)據(jù)的 Excel 表格數(shù)據(jù)也不會再出現(xiàn)網(wǎng)頁崩潰的問題了,同時處理速度也大大提升,1000 條數(shù)據(jù)在 4 分鐘內(nèi)可以處理完畢。

          4 小結(jié)

          回到最開始,JSZip 占用的問題依然存在,我們依然需要進(jìn)行分包,不過分包的大小可以提升到1000條數(shù)據(jù)。

          但是我們可以看到,如果不能找到問題的根本所在,一開始就進(jìn)行分包也無濟(jì)于事。

          網(wǎng)頁顯示“喔唷,崩潰啦!”怎么辦?請別著急,仔細(xì)分析才能解決問題。

          1. JavaScript 重溫系列(22篇全)
          2. ECMAScript 重溫系列(10篇全)
          3. JavaScript設(shè)計(jì)模式 重溫系列(9篇全)
          4. 正則 / 框架 / 算法等 重溫系列(16篇全)
          5. Webpack4 入門(上)|| Webpack4 入門(下)
          6. MobX 入門(上) ||  MobX 入門(下)
          7. 120+篇原創(chuàng)系列匯總

          回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~

          點(diǎn)擊“閱讀原文”查看 120+ 篇原創(chuàng)文章

          瀏覽 126
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  99久久久无码囯产精品 | 1234精品视频在线观看 | 欧美偷拍最新合集视频 | 无码xxxxx | 亚洲三级片无码高清 |