達達快送小程式效能最佳化實踐

陶然陶然發表於2023-01-19

  1. 背景

  達達集團是中國領先的本地即時零售與配送平臺,達達快送小程式作為公司重要的 ToC 業務入口,對外提供幫取幫送、跑腿幫買、幫排隊等服務,承擔了 ToC 業務較高部分的訂單量。對於小程式而言,效能至關重要。

  面臨什麼問題

  使用者開啟率偏低。以微信平臺為例,開啟率是指在小程式冷啟動的情況下,點選小程式到首屏渲染完成的百分比。程式碼包越大,啟動耗時越長,白屏時間越久,使用者越可能因為失去耐心而退出小程式,在轉化率不變的情況下,訂單量越低。

  效能不達標。如果效能不達標會帶來以下兩點影響:

  影響小程式流量獲取

  影響使用者體驗,進而降低使用者留存

  不同平臺小程式效能指標構成不盡一致,但主要有三個維度考慮:啟動效能、網路效能、執行效能,其中網路效能主要包含請求耗時及請求錯誤率,和介面質量以及使用者網路狀況強相關,所以此次效能最佳化的重點放在啟動效能以及執行效能。

  2. 問題識別

  2.1 “碎片化”最佳化

  “碎片化”主要指最佳化動作過於離散,不連貫無法形成體系。

  過去在啟動速度不達標時,也會按照小程式平臺開發者工具建議最佳化,額外也有些分包、縮包、圖片壓縮等動作,但有侷限性無法形成合力,依舊存在無法解決的問題:

  最佳化效果有限,無法達到「優秀」官方評測結果;

  啟動速度在需求迭代中反彈;

  過於定製化無法陳定並固化至後續需求研發中;

  2.2 效能指標難保持

  增加啟動階段的理解、利用好開發者工具、借鑑官方啟動最佳化實踐,透過常規動作大機率可以實現一段時間啟動效能指標的下降。但要實現指標長期穩定,依舊存在問題:

  指標監控體系缺失:小程式後臺雖然會提供效能資料,但資料散落在各個平臺,很難在業務迭代中持續關注並跟進。另外一旦指標波動,使用者第一時間就會感知,體驗下降,而研發是“後知後覺”的;

  業務需求迭代包體積增加:過去3個季度,達達快送小程式的發單場景由 2個 -> 8個;

  碎片化:“碎片化”的最佳化實踐,不成體系無法系統性解決效能問題;

  團隊成員變動:相關文件少,人員變動時無法有效沉澱;

  ......

  2.3 小程式效能分析

  本地開發中微信小程式提供了體驗評分工具它會在小程式執行過程中實時檢查,分析出一些可能導致體驗不好的地方,並且定位出哪裡有問題,以及給出一些最佳化建議。支付寶小程式可以使用全息檢測。  

  

  除了本地開發我們可以參考官方後臺,評分工具是在本地執行小程式程式碼時進行分析,但效能資料往往需要在真實環境和大資料量下才更有說服力。恰巧,小程式管理平臺 開發者提供了大量的真實資料統計。

  3. 關鍵路徑

  雖然不同平臺對小程式啟動耗時的各有一套定義,但往往也只是對啟動耗時終點定義不一致,小程式的啟動流程非常類似,大致會包含以下四步:

  小程式相關資訊準備

  框架資源準備

  業務資源準備

  載入渲染

  以微信小程式為例,啟動耗時指標統計的終點是生命週期onReady作為時間的結束,比較趨近於FCP(First Contentful Paint)指標。而支付寶小程式則更加趨近於TTI(Time to Interactive)指標。

  FCP:首次繪製任何文字,影像,非空白canvas或SVG的時間點;

  TTI:度量從頁面開始載入到主要的子資源載入完成並且能夠快速可靠地響應使用者互動的時間;

  啟動效能指標是個綜合結果體現,不同階段會使用者、平臺以及小程式本身的影響。因此我們以支付寶平臺提供的全息檢測工具,梳理了各個細分階段影響因素。

  階段定義:

  setUp:應用初始化,主要是db查詢時間;

  Update:查詢更新資訊,對比差異;

  offine: 下載離線包;

  waitLoadApp:解壓,等待渲染  

  分析各個階段影響因素確定四個核心最佳化思路:

  靜態資源最佳化,控制總包、主包、分包大小;

  介面聚合,合併介面並儘可能序列改並行,縮短最短請求路徑;

  啟動頁模組調整,分析啟動頁功能模組,在不影響業務流程前提下,最佳化互動方式,提升頁面渲染效能;

  沉澱傳承,總結歸納優秀實踐,持續保持優秀效能指標

  3.1 靜態資源最佳化

  如上文所述,資源包體積對小程式包下載、包解壓、程式碼注入等的多個啟動階段都有不同程度的影響。而且小程式平臺對包體積大小也有明確限制,以微信平臺為例:

  整個小程式所有分包大小不超過 20M;

  單個分包/主包大小不能超過 2M。

  所以資源包體積大小對啟動效能也尤為重要,因此選擇【靜態資源最佳化】作為第一步最佳化動作。

  3.2.1 包體積最佳化

  核心思路:從包載入時機和包體積大小兩個維度思考。對應動作分別是:預載入、縮包、分包非同步化。

  預載入:主要指微信小程式平臺,透過平臺提供的預拉取能力,在不影響主包的情況下將分包載入時機提前,提升分包頁面的載入速度。

  縮包

  分包:將相對獨立的頁面和元件拆分到分包,可以解決主包體積受限問題。但隨著業務的迭代實際開發中會遇到主包即使頁面很少也會過大,經過長期的實踐沉澱出一套適合我們的分包策略。  

  無用檔案、函式、樣式剔除:業務迭代無法避免會產生無用檔案,小程式可以入"lazyCodeLoading":"requiredComponents"(在開啟「按需注入」特性的前提下,「用時注入」可以指定一部分自定義元件不在小程式啟動時注入,而是在真正渲染的時候才進行注入),我們也可以用工具分析沒有用到的檔案和依賴,進行刪除

  延遲載入:分包一定程度可以縮減主包體積,但也遇到:

  外掛無法實現分包處理

  多業務的分包難以劃分

  所以我們採用了分包非同步化(該能力目前只在微信小程式中有)使用componentPlaceholder佔位,非同步拉取分包載入,完成分包下載和注入後,將佔位元件替換成真正的元件。

  3.2.2 圖片資源處理  

  壓縮圖片:上傳的圖片可以使用二倍圖(當裝置畫素比很大時,圖片會被放大,而放大會讓圖片看起來模糊。為此,我們可以使用二倍圖的方式來提高圖片的清晰度)並且壓縮,大圖片不要超過100KB。利用一些壓縮技術對圖片進行壓縮推薦 ,壓縮尺寸可觀,但對圖片顯示質量影響甚微。

  小圖片使用IconFont:避免小圖片作為CDN的情況,因為HTTP一個域名下有請求併發限制,過多圖片會造成隊頭阻塞。可以使用IconFont和base64等方式。

  大圖片統一使用CDN:在圖片處理中,因為我們遇到情況是大部分都是運營配置的圖片,可以在配置的後臺限制大小,自動轉化成webp格式(webp它可讓網頁圖檔有效進行壓縮,同時又不影響圖片格式相容與實際清晰度,進而讓整體網頁下載速度加快)。

  懶載入圖片:螢幕外的圖片可以使用懶載入,只有下拉之後才去載入對應的圖片。

  3.2 介面聚合&&時序最佳化

  在小程式中,發起網路請求是利用wx.request來傳送的,不同於瀏覽器一個域名併發的限制,wx.request呼叫的併發限制為10。超出限制的請求會被阻塞。所以針對介面我們主要採取的舉措有:

  實時性較低的介面快取結果:可以採用的策略是,頻繁使用的資料快取到記憶體,實時性較低的結果快取到本地,下次啟動可以讀取到記憶體中繼續使用,也可以給快取設定一個時效,更新本地快取

  減少介面序列:介面沒有依賴關係的可以考慮使用Promise.all

  預拉取首屏資源:預拉取能夠在小程式冷啟動的時候提前向第三方伺服器拉取業務資料,當程式碼包載入完時可以更快地渲染頁面,減少使用者等待時間

  介面合併,最佳化速度:分析介面詢問後端是否可以合併介面,最佳化稍慢的介面

  小結:在分析介面層面時,我們整理了小程式首頁的介面呼叫的時序圖:

  最佳化前: 總共使用者進入小程式後 21個(埋點介面和個端差異介面未計算在內)

  最佳化後: 總共使用者進入小程式後 17個(埋點介面和個端差異介面未計算在內)

  對比最佳化的結果由原來的序列長度為10->6,介面總數減少4個,並加入了介面快取,預拉取,本次最佳化在支付寶大約帶來了500ms的下降。

  3.3 啟動頁模組調整

  不管是微信還是支付寶小程式啟動速度的考量並不單單是首頁的耗時,包含所有入口頁面。達達小程式有檢視訂單詳情,活動頁等都會作為啟動頁投放。我們對業務梳理針對性的做了最佳化:

  首頁

  首頁預先拉取了金剛位,banner,廣告位等資源,因為實際呼叫中獲取這些資源鏈路比較長,我們冷啟動中獲取資源在小程式啟動直接渲染,在真實呼叫中去比較資料的變化,增量更新,雖然首頁是千人千面的頁面,但是絕大多數內容是類似的,提前渲染可以提升總體載入時間;

  對於獲取位置資訊是比較耗時的,我們在使用者授權後快取了結果到記憶體,並且存入本地設定了一個時效,在使用者下次開啟時,未過期的情況下可以直接讀取本地I/O。考慮到位置資訊需要呼叫多個介面獲取且較慢,所以提升較大;

  在分析包大小時發現主包存在過大的SDK,但沒有辦法去除,或者利用plugin方式載入。最後是將涉及外掛的SDK拆到分包中利用分包非同步化去載入;

  首頁彈窗邏輯之前有5種+,透過讓後臺承擔更多的業務邏輯,可以節省小程式前端程式碼量,以前的做法是前端從不同介面獲取資源,然後透過優先順序去展示,前端做很多邏輯處理,現在有後端實現了一套廣告位系統,減少了介面呼叫和邏輯判斷。  

  物流詳情頁

  針對天降紅包,因為他序列3個介面,影響較大。我們執行了發券使用者操作之後去載入紅包;

  針對地圖的展示,去除了非必要的路徑規劃,摺疊展示了地圖

  本次業務流程的最佳化,在支付寶小程式總體降低了400ms  

  3.4 優秀實踐

  “突擊最佳化”一定程度上能夠提升效能指標,但持續保持效能指標的穩定則功在平時。因此除了固化一些專項最佳化策略,比如:分包策略、圖片處理策略等,還需要沉澱更多實踐並傳承。

  流程類:

  建立指標監控體系:主要包含:包大小、圖片大小、啟動耗時、評測結果。過去研發對於指標的波動是“後知後覺”的,指標監控利於研發儘早發現問題,減少對使用者影響。

  規範發版:除了程式碼包體積程式碼注入、首屏渲染之外,發版頻率等因素也會影響小程式啟動耗時,透過與業務方確認在不影響小程式正常功能迭代的前提下,約定每週2次固定發版。

  程式碼類:

  要提升渲染效能就不得不瞭解小程式的架構:  

  可以從圖中看出,由於渲染層與邏輯層分開,一個小程式有多個介面,所以渲染層對應存在多webview。這兩個執行緒之間由Native層進行統一處理。無論是執行緒之間的通訊、資料的傳遞、網路請求都由Native層做轉發。所以如何減少資料互動的頻率和大小是提升渲染效能的關鍵。

  程式碼類:

  合併setData呼叫:儘可能合併setData的呼叫,將多次setData合併為一次,可以模仿vue的nextTick寫合併的邏輯(呼叫 setState 時提供的物件會被加入到一個陣列中,當下一次事件迴圈執行的時候再把這些物件合併一起,透過 setData 傳遞給原生小程式),支付寶小程式可以呼叫batchedUpdates來批次更新,減少呼叫次數;

  減少setData大小:傳輸的資料量越多,執行緒間通訊的耗時越長,渲染速度就越慢,我們的做法是將不設計渲染的資料放入_data中;

  去掉不必要的屬性節點,繫結屬性資料大小:在xml中繫結屬性data-xxx,儘量減少資料的大小,檢視層會把事件 target 和 dataset 資料傳輸給邏輯層。那麼,當自定義資料量越大,事件通訊的耗時就會越長;

  JSAPI呼叫限制:一些同步API會阻塞渲染,啟動頁面減少使用 Sync 結尾的同步 API ,getSystemInfoSync, getStorageSync,setStorageSync。可以快取結果,或者使用非同步獲取資料。原則就是:減少使用,快取結果。

  依賴庫最佳化:刪除了埋點框架中一些非必要的同步API的獲取操作,或者延後執行,將頻繁呼叫的API結果快取到記憶體中,減少呼叫

  ......

  4. 總結&規劃

  我們來梳理一下整體的最佳化思路,如下圖所示:  

  4.1 成果

  微信平臺

  啟動耗時降低20%;

  過去兩個季度,啟動耗時長期維持在優秀;

  開啟率提升0.5%

  支付寶平臺

  C端支付寶小程式 【達達快送】啟動耗時降低40%,現在維持在優秀水平。

  服務競爭力指數 SCI (支付寶平臺):提升至滿分。

  4.2 規劃

  經過本次最佳化微信和支付寶小程式都達到了官方的優秀指標,最佳化的經驗適用所有小程式。但如何監控啟動速度,如何結合自身業務定義小程式效能指標,出現問題及時告警,能夠定位具體的原因,需要建立一套自己監控體系,持續保持小程式效能。

來自 “ 達達集團技術 ”, 原文作者:孔華超 徐文浩;原文連結:http://server.it168.com/a2023/0119/6786/000006786983.shtml,如有侵權,請聯絡管理員刪除。

相關文章