因事件堵塞導致頁面卡頓

記得要微笑發表於2021-12-14

概述

上週星期四(2021/12/09)開始陸續有供應商反饋賣家中心頁面公共模組(選單欄)存在卡頓問題,特別是在進入商家報價頁面,但是開發與測試在轉測、轉演、灰度階段均未發現該效能問題。

kadun.gif

分析

首先,我們需要了解頁面的實現架構,賣家中心商家報價頁面的公共模組ftl與右側內容區ftl是通過Sitemesh框架整合而成的,公共模組ftl只定義了<div id="seller-topbar"></div><div id="seller-sidebar" class="menus"></div>的空架子,其元素內容通過引入執行seller-react-frame.js將元素內容注入到相關元素標籤中。

另外,注入的元素內容並不是在seller-react-frame.js中實現的,而是在這個指令碼中引入了其他指令碼,引入的這些指令碼是React實現topbar、slider元件後經webpack構建生成的。

右側內容區是切切實實使用freemarker模板引擎實現的,資料由後端注入到頁面中,相當於服務端渲染。

瞭解請求頁面情況後,我們通過networkperformance效能分析看看

network分析

image-20211213152937288.png

image-20211213153300120.png

network皮膚可以看出,公共模組中的一個指令碼原始大小有1.3Mgzip壓縮後傳輸大小為375KB,從disk cache(磁碟快取)讀取耗時2.78s,清除快取從CDN請求耗時2.88s,而公共模組其他的指令碼原始大小都很小,只有一點幾KB,請求耗時只有一兩百毫秒。

顯而易見,這個指令碼過大了,需要做程式碼拆分。另外,從disk cache中讀取也需要耗時,改用走memory cache(記憶體快取),因為memory cache更快。

performance分析

在通過Performance檢測頁面效能發現公共模組(選單欄)渲染的事件迴圈前面有一個執行耗時很長的事件 迴圈,這個事件迴圈是在初始化四級地址和品牌選項,四級地址樹我們使用的ZTree.js處理的,裡面init方法初始化樹節點的事件複雜度比較高,因此我們看到檢測到的執行時間較長(接近3秒) ,這更加堵塞了後面選單欄事件迴圈的執行。

image-20211213181636064.png

鑑於業務需求,四級地址樹節點可以不用在剛進入頁面時初始化,因此我將其指令碼請求和執行放在了onload函式中,但是通過上圖發現四級地址初始化還是先於渲染選單欄執行,這是為什麼呢?

image-20211213183218733.png

image-20211213182723881.png

網路請求皮膚看一下指令碼獲取的先後順序,發現公共模組指令碼先於四級地址指令碼獲取,這使我更加困惑了。這時想到左側選單欄是React實現的,選單欄資料是通過介面獲取的,而不是像freemarker模板引擎是通過後端注入資料的,然後排查獲取選單介面發現,為了獲取到選單欄資訊,竟然存在三個介面的序列呼叫,因為介面的序列呼叫導致渲染選單欄的任務晚於四級地址初始化的任務加入到任務佇列中,再加上四級地址初始化耗時較長,從而引起使用者感知左側選單欄卡頓。

解決方案

(1)對公共模組中1.3M的指令碼做程式碼拆分;

(2)優化指令碼中的介面序列呼叫;

(3)從disk cache讀取改成從memory cache讀取;

(4)因為網路請求耗時不穩定,無法確保渲染選單欄事件迴圈先於四級地址樹節點初始化事件迴圈,因此可以在請求選單欄介面成功後通過postMessage或者自定義事件通知可以開始初始化四級地址樹節點;

相關文章