事情的原由是咱們WMS系統內有一個批量打印的功能,今天倉庫反應第一次打印的速度大概是2s,可是以後每次都愈來愈慢,到後面頁面基本就直接卡死了。前端
從這個表現來看,這個問題基本能夠定位成性能問題,而不是能夠被try...catch到的異常。web
想到的解決方案有兩種:chrome
一直沒找到什麼實踐機會來使用這部分功能來定位問題,此次有了真實的業務場景,果斷但願能用第二種方案來準肯定位到問題。element-ui
從表現上來看,感受像是每次批量打印的時候致使了一部份內存泄漏,而後內存佔比愈來愈高致使瀏覽器卡死。canvas
這時候就須要用Chrome的Memory功能來統計下內存佔比。在Memory下選擇Take heap snapshop,分析完成以後能夠看到當前頁面的各類對象的內存佔比。當前我關注的不用那麼細,只須要關注到頁面的總內存,我在每次批量打印完成後都從新統計了頁面佔的內存,能夠發現:每次內存佔用有輕微上升,但確定不會致使頁面卡死。至此,能夠排除掉是內存泄漏致使的問題。瀏覽器
排除到內存泄漏的問題後,我能想到的頁面被卡住的緣由是JS腳本的執行時間過長。由於瀏覽器的渲染是單線程的,若是當前瀏覽器在進行JS腳本計算,那麼在這個過程當中UI線程是無法同時進行渲染改變的,因此看起來就是頁面卡頓了。微信
這時候就須要用Chrome的Timeline分析工具(新版本Chrome裏改爲Performance)來查看每個函數調用的時長,來定位出問題的具體函數。markdown
點擊record按鈕以後,而後屢次調用批量打印功能,結束錄製。獲得瞭如圖的分析結果:app
從圖中能夠明顯看出第一次打印到第三次打印耗時增長不少,其中黃色部分表明腳本執行時間,紫色部分表明渲染時間。增長的時間部分主要是腳本執行時間致使的,這時候須要定位具體是哪一個函數致使的腳本執行時間增長。chrome-devtools
這時候能夠查看火焰圖部分,橫座標表明了消耗時間,縱座標是調用棧關係,上面的棧調用下面的棧。一直從上往下找到最內層的函數調用,發現了致使耗時增長的函數是JsBarcode
,一個生成條形碼的函數。
爲了驗證這個結論,在代碼裏先註釋掉這個函數,從新執行Timeline分析。獲得如圖的分析結果:
能夠看到由於腳本執行致使的時間增長問題已經解決了,可是渲染的時間仍是隨着每一次的打印都會增長,這時候開始分析渲染的問題。查看渲染部分詳情能夠看到右上角的一個三角形,這個三角形表明這裏存在異常,而且Chrome給出了相應的警告(Forced reflow):
也就是說這裏強制重繪了界面,可是至此仍是沒理解爲何會從新繪製頁面,這裏強大的Chrome直接給出了影響渲染的代碼片斷,scrollbar-width這個文件是element-ui的一個工具函數。
這時候查看element-ui源碼對這個文件的引用狀況,一層層往上定位發如今當前頁面使用到的table組件和message-box組件裏都引用到了這個文件。table組件會在列表數據刷新的時候調用到這個函數,而message-box會在彈出的時候調用到這個函數。
爲了驗證這個猜測,註釋掉列表更新和彈框的代碼,從新使用Timeline分析,發現剛纔的三角形不見了,這時候頁面被從新繪製的問題也找到了。
至此,致使增長打印時長的兩個問題 1. 腳本執行 2. 頁面渲染 都已經被定位到了,可是致使問題的業務代碼還沒改呢!也就是爲何繪製條形碼的函數和重繪頁面的時間會愈來愈長呢?
問題已經分析到這了,很輕易想到了這部分功能裏惟一一句相關的DOM操做代碼,在每次打印一張快遞單的時候都會appendChild一段DOM到body上(爲了繪製二維碼以及轉canvas導出圖片),可是每次appendChild以後並無去remove掉這段冗餘的DOM(逃。
回滾debugger的時候的修改代碼,添加removeChild操做。從新執行Timeline分析,能夠看到三次打印的耗時已經一致了。明天讓QA小哥哥測試一下能夠上線了~
最終定位到錯誤比較低級,不過此次實踐基本是從Chrome強大的性能分析工具定位到了問題,雖然若是採用方案1去review code來排查最終也能定位到問題。可是能夠想象,當業務代碼足夠複雜,函數調用層級很深的時候,去review code來排查的效率就會遠不如利用Timeline分析的效率高了。
今天聽了雲音樂的校園十佳,寫了一篇博客,突然想吟詩一首,苟利國家生死以(逃
author by yeomanyang