1. 程式人生 > 其它 >使用工具分析 SAP UI5 應用前端執行的效能問題

使用工具分析 SAP UI5 應用前端執行的效能問題

這是 Jerry 2021 年的第 66 篇文章,也是汪子熙公眾號總共第 343 篇原創文章。

國慶黃金週開始的前一天,9月30日,我所在的開發團隊收到了一個關於 Angular 應用的伺服器端渲染(Server Side Render,簡稱為 SSR)的客戶 incident,讓我有機會學習如何使用 Chrome 開發者工具來分析 Web 應用的效能問題。

Jerry 之前曾經寫過一篇關於 Chrome 開發者工具的文章:Jerry和您聊聊Chrome開發者工具,本文算是該文的後續。


本來我是想用 Angular 應用為例來介紹工具的用法,但考慮到本公眾號一萬多讀者裡面,絕大多數前端開發朋友們,使用的還是 SAP UI5,因此最後還是選擇了基於 SAP UI5 應用來介紹使用 Chrome Dev Tools 進行 Web 應用效能分析的使用步驟。

本文提及的 SAP UI5 應用,指通過 FreeStyle 方式開發的 SAP UI5 應用。通過 Fiori Elements 開發的 SAP UI5,不在本文討論之列。

根據我以往的工作經驗,如果一個 SAP UI5 應用出現了效能問題,很多時候效能瓶頸都出在該應用消費的後臺 API,比如 OData 服務或者其他 AJAX 呼叫。

同 Angular 相比,SAP UI5 框架為應用開發人員遮蔽了 Web 前端開發中的很多底層細節,比如 DOM 操作,CSS 的編輯,資料雙向繫結和事件註冊等邏輯,均使用 UI5 封裝之後的方式來完成。因此一個 SAP UI5 應用,純粹的前端程式碼裡,由於應用人員編碼失誤導致效能問題的概率相對 Angular 要低得多。

因此,為了演示 Chrome 開發者工具進行 SAP UI5 效能分析的使用方法,我在自己的 SAP UI5 腳手架應用裡,故意編寫了一些會引起效能問題的前端程式碼,然後通過 Chrome 開發者工具,把這些導致效能問題的程式碼進行定位。

我這個 SAP UI5 腳手架應用可以通過如下 url 訪問:

https://wangzixi-diablo.github.io/ui5-toolset/webapp/index.html

這個 UI5 應用的檢視我採取 JavaScript 檢視型別實現,在檢視實現檔案 App.view.js 的 createContent 方法裡,我呼叫了一個函式 heavyFunction,該函式在一個 for 迴圈裡建立了一萬個 div 標籤,新增到 DOM 樹中,然後插入一億個元素到陣列中。


我期望的結果是,能夠使用 Chrome 開發者工具,對該 SAP UI5 應用進行效能分析,通過工具的幫助,將效能問題快速定位到這個 heavyFunction 函式。

其實使用 Chrome 開發者工具的 Performance 面板對 Web 應用進行效能分析,使用方式和 SAP ABAP 資料庫效能分析工具 ST05 非常類似,即開啟跟蹤模式,在該模式下執行資料庫事務(Web 應用),然後關閉跟蹤模式,然後分析 ST05 (Chrome 開發者工具) 輸出的跟蹤結果。

首先開啟一個 Chrome 隱身視窗,這是為了排除 Chrome 安裝的其他擴充套件對效能分析可能造成的影響。

開啟 Chrome 開發者工具,選擇 Performance 標籤頁,開啟設定選項,Network 選擇成 Slow 3G,CPU 選擇成六倍速降低:6x slowdown.

然後點選 Record 圖示,開啟效能跟蹤模式:

重新整理應用,使其在效能跟蹤模式下執行:

等待頁面顯示完畢後,點選 Stop 按鈕,關閉跟蹤模式。
然後我們就能看到下圖所示的跟蹤結果:


大家請看下圖代表 CPU 執行活動的這根條狀圖,其中在兩個時間點之內,有大量密集的指令碼執行(scripting)和渲染(rendering)的活動記錄。


我們首先詳細分析,為什麼會有如此密集的 scripting 操作。移動下圖所示的兩根滑動條,縮小我們排查問題的時間戳範圍(range).


時間戳範圍越小,顯示的明細越具體。大家注意到上圖我用紅色矩形框高亮的 Main 下拉框了嗎?該下拉框之下,顯示的就是在指定的左右時間戳範圍內,Main 即主執行緒執行的 CPU 活動明細。

我們把 Main 下拉框顯示的內容拖至底部,一下子就發現了我們故意編寫的 heavyFunction 赫然在列,在我們指定的時間戳範圍內,總共花費了 6.799 秒的時間去執行。

點選 App.view.js 的超連結,還能直接跳轉到對應的程式碼去:

下面我們再調整左右時間戳滑動條,來研究 Rendering,即下圖紫色條代表的活動。我們觀察到,每一根紫色條,右上角都有一個紅色三角形圖示。滑鼠放上去,tooltip 會顯示:Forced reflow is a likely performance bottleneck.

意思是,強制迴流是應用一個可能的效能瓶頸。

上圖我們能觀察到 Recalculate Style 和 Layout 紫色條,分別是 Rendering 的兩種不同的操作型別。

我們在程式碼編輯器裡編寫的 HTML 程式碼,在從伺服器端被載入到瀏覽器並被解析,到呈現在終端使用者眼前,需經歷上圖所示的幾個步驟:執行 HTML 頁面裡的 JavaScript 程式碼,構建 DOM 樹,將文字格式的 CSS,轉換成瀏覽器可以理解的資料結構,計算元素樣式,生成渲染樹,遍歷渲染樹,計算渲染樹中每一個節點的大小和位置,建立待繪製列表,最終進行繪製(Paint)和合成(Composite).

而 Web 應用在使用過程中,由於使用者與頁面互動,導致 JavaScript 程式碼執行,可能會使得頁面元素的大小及位置等屬性發生改變,從而觸發瀏覽器重新計算佈局,最終重新渲染頁面。我們稱瀏覽器這種行為叫做迴流(reflow),即我們在上圖 Chrome 開發者工具裡觀測到的警告資訊:

Forced reflow is a likely performance bottleneck.

回到我們的例子,受到迴流操作影響的元素總數為 10087,觸發迴流操作的程式碼:ResizeHandler-dbg.js.

為什麼檔案 ResizeHandler-dbg.js 的第 170 行會觸發瀏覽器迴流呢?我們直接單擊上圖的超連結,可以直接定位到第 170 行程式碼。

首先,在 Bar-dbg.js 的 onAfterRendering 鉤子函式(綠色)裡,會呼叫 _handleResize(黃色), 檢測當前是否應該丟擲 "resize" 事件。這個檢測最終被投遞交給 ResizeHandler.checkSizes(橙色)進行處理。

Resize 檢測邏輯也很簡單,比較 DOM 元素新舊 width 和 height 是否相同。若不相同,則如下圖紅色矩形框內程式碼所示,觸發 resize 事件。

獲取 DOM 元素新的寬度的程式碼正好位於 170 行,這行程式碼訪問了元素屬性 offsetWidth.

按照這篇文件的記錄,下列屬性或方法被 JavaScript 呼叫時,會迫使瀏覽器以同步的方式重新計算樣式,觸發佈局操作即迴流。

https://gist.github.com/paulirish/5d52fb081b3570c81e3a

瀏覽器這一機制本身沒有什麼問題,但是如果某個時間點,有大量的頁面元素的上述屬性被訪問時,則很可能成為效能瓶頸。

回到本文的例子,因為我在 heavyFunction 函式裡插入了一萬個 div 元素,在 resize 檢測時,這一萬個元素的 offsetWidth 屬性被訪問,造成了瀏覽器迴流的不斷觸發,最終導致了大量的 CPU 時間被花費在了 rendering 之上。

總結

本文介紹的使用 Chrome 開發者工具來分析 Web 應用效能問題的步驟,只是該工具使用技巧的冰山一角。後續有機會,Jerry 會繼續把我在日常工作中學到的東西分享出來。

如果遇到 SAP UI5 應用出現效能問題,優先排查效能瓶頸是否由後臺 API 造成。對於 SAP UI5 應用的前端實現來說,因為 UI5 已經為應用開發人員做出了良好的封裝,因此絕大部分情形,應用開發人員無需手動操縱 DOM 元素和 CSS 樣式,所以也不大可能出現類似本文 heavyFunction 函式裡模擬的極端情況。

無論如果,如果你懷疑你的 SAP UI5 應用的前端也可能有效能問題,此時無需胡亂猜測,用本文介紹的步驟一試便知分曉。

感謝閱讀。


Jerry 的 SAP UI5 專題

更多Jerry的原創文章,盡在:"汪子熙":