初級前端小程序項目加載速度優化 - 新聞資訊 - 雲南小程序開發|雲南軟件開發|雲南網站建設-昆明融晨信息技術有限公司

159-8711-8523

雲南網建設/小程序開發/軟件開發

知識

不(bù)管是(shì)網站,軟件還是(shì)小程序,都要(yào / yāo)直接或間接能爲(wéi / wèi)您産生價值,我們在(zài)追求其視覺表現的(de)同時(shí),更側重于(yú)功能的(de)便捷,營銷的(de)便利,運營的(de)高效,讓網站成爲(wéi / wèi)營銷工具,讓軟件能切實提升企業内部管理水平和(hé / huò)效率。優秀的(de)程序爲(wéi / wèi)後期升級提供便捷的(de)支持!

您當前位置>首頁 » 新聞資訊 » 小程序相關 >

初級前端小程序項目加載速度優化

發表時(shí)間:2021-3-31

發布人(rén):融晨科技

浏覽次數:90

這(zhè)份文字是(shì)根據近期團隊做來(lái)問丁香醫生 SPA 和(hé / huò) 丁香醫生小程序 加載速度優化的(de)經曆整理而(ér)成。

效果

古人(rén)有一句話叫做:治感冒看療效。既然是(shì)關于(yú)速度優化的(de),我們就(jiù)先來(lái)看一下優化的(de)效果。

來(lái)問丁香醫生

Chrome Network

選取了(le/liǎo)訪問量較大(dà)的(de)首頁和(hé / huò)我的(de)頁面進行随機取樣,通過下圖可以(yǐ)看到(dào)首頁的(de)加載時(shí)間從 5.1s 下降到(dào) 1.67s,我的(de)頁面從 2.92s 下降到(dào) 1.82s。

mta

2018.01.02 早上(shàng)的(de)頁面響應速度數據,目前國(guó)内各省份平均加載速度在(zài) 0.99~2s(雖然沒有達到(dào) 1s 内加載,但是(shì)以(yǐ)目前業務量級,這(zhè)樣的(de)速度是(shì)可以(yǐ)被接受的(de)):

前者這(zhè)是(shì) Google 的(de)一個(gè)評分工具,最開始做優化時(shí)用它測了(le/liǎo)一些頁面的(de)分數。後來(lái)發現了(le/liǎo)後面這(zhè)些 Chrome 插件。讓我困惑的(de)是(shì)同樣的(de)頁面這(zhè)幾個(gè)工具給出(chū)的(de)結果分數都不(bù)一樣。手淘 的(de)首屏加載速度挺快的(de),但是(shì)跑出(chū)來(lái)的(de)分數也(yě)不(bù)高。最終我隻是(shì)選擇性的(de)參考一下工具給出(chū)來(lái)的(de)建議,忽視了(le/liǎo)其給出(chū)的(de)評分。

丁香醫生小程序

對于(yú)小程序,做了(le/liǎo)優化後得到(dào)部門同學的(de)反饋是(shì)這(zhè)樣的(de):

具體的(de)數據指标如何呢?雖然目前沒有特别好用的(de)性能檢測方式(包括官方提供的(de)性能檢測工具在(zài)内),最終我們組的(de)舒哲同學還是(shì)利用官方提供的(de)工具做了(le/liǎo)一下簡單的(de)數據對比,數據如下:

在(zài)不(bù)影響産品需求正常叠代的(de)前提下,兩個(gè)項目的(de)優化斷斷續續持續了(le/liǎo)兩周。整體上(shàng)來(lái)說(shuō),本次優化的(de)性價比還是(shì)較高的(de)。

爲(wéi / wèi)什麽做加載速度優化?

直接原因很簡單:慢。雖然說(shuō)頁面加載速度并沒有達到(dào)慢的(de)讓人(rén)無法忍受,但至少沒辦法讓人(rén)說(shuō)加載很快。

既然明知道(dào)加載速度不(bù)快,那之(zhī)前在(zài)幹什麽?爲(wéi / wèi)什麽不(bù)早早的(de)去做優化呢?

這(zhè)是(shì)一個(gè)好問題,我曾經在(zài)深夜中問過自己多次。我給自己的(de)答案是(shì):首先,要(yào / yāo)承認自身技術水平和(hé / huò)經驗的(de)限制,如果是(shì)一個(gè)在(zài)前端戰場上(shàng)身經百戰的(de)人(rén)一直在(zài)負責項目的(de)叠代,或許情況會比優化前好一些。 其次,之(zhī)前整個(gè)産品線的(de)項目一直處于(yú)探索和(hé / huò)快速叠代中,前端研發資源基本上(shàng)總是(shì)處在(zài)被需求排滿的(de)狀态下,産品需求快速上(shàng)線的(de)優先級是(shì)最高的(de)。正是(shì)因爲(wéi / wèi)産品的(de)整體節奏稍微放緩了(le/liǎo)一些,才讓研發資源有精力來(lái)做一些優化。

爲(wéi / wèi)什麽說(shuō)是(shì)前端響應速度優化,而(ér)不(bù)是(shì)前後端?

因爲(wéi / wèi)我是(shì)親眼看着這(zhè)兩個(gè)項目逐漸長大(dà)的(de),單從前端工程的(de)角度來(lái)審視,在(zài)自己的(de)認知範圍内,早就(jiù)認爲(wéi / wèi)項目中有一些地(dì / de)方是(shì)需要(yào / yāo)優化的(de)。堅定了(le/liǎo)先從前端動手的(de)想法,是(shì)因爲(wéi / wèi)讀了(le/liǎo)《高性能網站建設指南》這(zhè)本書,書中提到(dào)了(le/liǎo)一個(gè)性能黃金法則(Performance Golden Rule):隻有 10% ~ 20% 的(de)最終用戶響應時(shí)間是(shì)花在(zài)下載 HTML 文檔上(shàng)。話說(shuō)到(dào)這(zhè)個(gè)份上(shàng),還猶豫什麽呢,先從前端項目開始撸起袖子(zǐ)加油幹吧。

之(zhī)前去 Qcon 等技術大(dà)會上(shàng),聽過幾次關于(yú)加載速度的(de)分享。比如:使用 HTTP2,整站級别的(de)前後端優化等。方案确實是(shì)好的(de)方案,但具體是(shì)否要(yào / yāo)應用到(dào)自己團隊實際項目中,還得根據執行成本、團隊技術儲備等維度從長計議。

爲(wéi / wèi)什麽說(shuō)是(shì)初級?

因爲(wéi / wèi)深感自己在(zài)前端性能優化這(zhè)個(gè)領域還有很長的(de)路要(yào / yāo)走。

如何做的(de)?

前戲這(zhè)麽長,終于(yú)可以(yǐ)開始了(le/liǎo)。

來(lái)問丁香醫生 SPA

先看圖(綠色部分爲(wéi / wèi)已在(zài)項目中應用的(de)方法):

實現遊客機制

最初來(lái)問丁香醫生是(shì)基于(yú)微信服務号做的(de),當時(shí)的(de)設計是(shì)用戶通過服務号菜單進入應用時(shí),會自動幫他(tā)進行跳轉登錄,登錄成功後服務端再重定向回到(dào)應用。登錄這(zhè)個(gè)環節,雖然與項目代碼層面的(de)加載優化關系不(bù)大(dà),但是(shì)從用戶體驗的(de)角度這(zhè)樣的(de)流程是(shì)不(bù)好的(de)。因爲(wéi / wèi)相比于(yú)直接打開頁面,用戶需要(yào / yāo)等更長的(de)時(shí)間,并且會看到(dào)兩次頁面加載的(de)進度條。從産品的(de)角度,一些頁面是(shì)不(bù)需要(yào / yāo)用戶登錄即可訪問的(de)。綜上(shàng),将登錄流程後置,讓用戶可以(yǐ)直接進入應用這(zhè)件事情,于(yú)情于(yú)理都是(shì)必須要(yào / yāo)做的(de)。

改造流程大(dà)緻爲(wéi / wèi):梳理産品現有流程 -> 用戶進入應用時(shí)取消強制登錄 -> 在(zài)産品流程核心環節進行用戶登錄狀态判斷并引導登錄。具體實現細節不(bù)再贅述。

減小資源包體積

實現了(le/liǎo)遊客機制後,接下來(lái)就(jiù)是(shì)對應用的(de)資源包動手了(le/liǎo)。因爲(wéi / wèi)通過 Chrome 開發者工具的(de) Network 可以(yǐ)看出(chū),下載 CSS、JS 資源還是(shì)占用了(le/liǎo)不(bù)少時(shí)間的(de)。下圖是(shì)減小資源包體積之(zhī)前的(de)情況:

優化前包體積大(dà)小-Gzipped

精簡第三方依賴

想要(yào / yāo)減少資源體積大(dà)小,首先需要(yào / yāo)知道(dào)哪些資源時(shí)應該/可以(yǐ)被删除的(de)。由于(yú)項目是(shì)基于(yú) Webpack 構建的(de),因此可以(yǐ)使用 Webpack Bundle Analyzer 進行分析Webpack 生成的(de)包體組成。然後根據實際情況進行移除就(jiù)好。

精簡了(le/liǎo)第三方依賴後,啓動應用時(shí)需要(yào / yāo)下載的(de)資源體積還是(shì)挺大(dà)的(de)。此時(shí)就(jiù)需要(yào / yāo)使用 Webpack 的(de)代碼分離和(hé / huò)懶加載進行進一步的(de)優化。

代碼分離

代碼分離的(de)思想就(jiù)是(shì)化整爲(wéi / wèi)零,将代碼分離到(dào)不(bù)同的(de) bundle 中,然後可以(yǐ)按需加載或并行加載這(zhè)些小的(de) bundle 文件。

代碼分離主要(yào / yāo)是(shì)利用 Webpack 的(de)動态導入

Webpack 目前有三種常用的(de)代碼分離方法:

  • 入口起點:使用 entry 配置手動地(dì / de)分離代碼。(優勢:簡單、直觀。劣勢:配置繁瑣、同一份代碼可能會被引入到(dào)各個(gè) bundle 中、不(bù)靈活,并不(bù)能将核心應用程序邏輯進行動态拆分代碼)
  • 防止重複:使用 CommonsChunkPlugin 去重和(hé / huò)分離 chunk。
  • 動态導入:通過模塊的(de)内聯函數調用來(lái)分離代碼。

經過對比之(zhī)後,最終選擇了(le/liǎo)動态導入的(de)方式。

動态導入(dynamic imports)

webpack 提供了(le/liǎo)兩個(gè)類似的(de)技術:

  • import() 語法(推薦,符合 ECMAScript 提案)
  • require.ensure(webpack 欽定)

示例

// 分離 lodash
async function getComponent() {
    const _ = await import(/* webpackChunkName: "lodash" */ 'lodash');
}

懶加載

懶加載是(shì)在(zài)代碼分離的(de)基礎上(shàng)更近了(le/liǎo)一步。

雖然我們可以(yǐ)将代碼進行代碼分離,但代碼分離後的(de) bundle 隻是(shì)加載的(de)優先級會不(bù)同,最終還是(shì)會加載,但實際情況是(shì)某些代碼在(zài)用戶進行某項操作之(zhī)前是(shì)不(bù)需要(yào / yāo)加載的(de)。比如:個(gè)人(rén)信息編輯頁面有一個(gè)用戶修改頭像功能,對于(yú)用戶來(lái)說(shuō),即使他(tā)進入了(le/liǎo)個(gè)人(rén)信息編輯頁面,在(zài)他(tā)未點擊上(shàng)傳按鈕之(zhī)前,用于(yú)上(shàng)傳頭像的(de)代碼是(shì)沒必要(yào / yāo)加載的(de)。

Vue-Router 結合 Vue 的(de)異步組件和(hé / huò) Webpack 的(de)代碼分割功能,實現了(le/liǎo)路由組件的(de)懶加載。

在(zài)經過精簡依賴、代碼分離和(hé / huò)懶加載之(zhī)後,項目的(de)資源包體積大(dà)小如下圖:

Gzipped:

用戶進入首頁需要(yào / yāo)加載的(de) js 資源從 vendor.js 、 main.js 和(hé / huò) chunks 共 672.84kb 變爲(wéi / wèi)隻需要(yào / yāo)加載一個(gè) 186kb 的(de) main.js 。

複用 Store 數據以(yǐ)減少網絡請求數量

來(lái)問丁香醫生是(shì)基于(yú)Vue.js 全家桶實現的(de),狀态管理用的(de)是(shì)Vuex。

之(zhī)前的(de)實現中,有些功能實現沒有很在(zài)意 Store 數據的(de)複用。比如:從 A 頁面進入 B 頁面後再返回 A 頁面時(shí),會再去獲取端獲取一次 A 頁面需要(yào / yāo)的(de)數據。這(zhè)種處理不(bù)僅僅是(shì)多發了(le/liǎo)不(bù)必要(yào / yāo)的(de)請求,如果在(zài)請求過程中做了(le/liǎo)一些頁面級别加載中的(de)處理,那麽每次切換頁面時(shí)都會讓用戶看到(dào) loading 效果,這(zhè)也(yě)會讓人(rén)覺得加載慢。既然用了(le/liǎo)狀态管理,那麽就(jiù)應該把他(tā)利用好才是(shì)。

本次優化過程中的(de)數據複用,主要(yào / yāo)是(shì)在(zài)部分請求 action 之(zhī)前增加邏輯判斷,如果 Store 中有當前操作需要(yào / yāo)的(de)數據,則不(bù)再調用 action 。

前後端徹底分離

關于(yú)這(zhè)一點會再寫一篇文章進行闡述。

丁香醫生小程序

老規矩,先看圖:

圖片資源

最開始做小程序時(shí),是(shì)把所有圖片資源 base64 後進行使用的(de),這(zhè)導緻了(le/liǎo)所有圖片資源最終都被打包到(dào)小程序的(de)安裝包中。所以(yǐ)做小程序的(de)加載速度優化的(de)第一步,就(jiù)是(shì)把一些體積較大(dà)的(de)圖片資源改爲(wéi / wèi)使用線上(shàng)資源。具體做法是(shì)将素材先上(shàng)傳到(dào) cdn,然後在(zài)小程序中直接使用線上(shàng)圖片地(dì / de)址。

登錄鑒權優化

原本小程序的(de)登錄是(shì)我們自己實現的(de)一套登錄方案,核心是(shì)前後端一起維護一個(gè)類似于(yú) SessionId 的(de) ID。服務端對于(yú)這(zhè)個(gè) ID 是(shì)設置了(le/liǎo)有效期的(de),而(ér)之(zhī)前前端的(de)實現是(shì)每次用戶啓動小程序,都直接去請求公司的(de) SSO 獲取一個(gè)新的(de) ID,沒有在(zài)意本地(dì / de)的(de) ID 是(shì)否過期。

優化的(de)點在(zài)于(yú)在(zài)應用啓動時(shí),增加對 ID 有效期的(de)判斷,從而(ér)避免每次用戶啓動都需要(yào / yāo)發請求獲取新的(de) ID。

預渲染

之(zhī)前在(zài)小程序所有需要(yào / yāo)從服務端獲取數據的(de)頁面,都實現了(le/liǎo)一個(gè)加載中的(de)效果,即請求未返回結果時(shí),整個(gè)頁面用戶隻會看到(dào)一個(gè)加載中的(de)菊花。如果某頁面隻有服務端提供的(de)元數據級别接口,沒有業務接口,并且接口返回的(de)數據是(shì)有依賴關系的(de),那麽用戶等待的(de)時(shí)間會大(dà)大(dà)加長。

仔細思考會發現,其實是(shì)沒有必要(yào / yāo)等所有接口數據回來(lái)後再給用戶呈現完整頁面的(de)。

最終的(de)優化方案分爲(wéi / wèi)兩種:一種是(shì)取消加載中效果,先給用戶呈現完整的(de)利用本地(dì / de)數據渲染好的(de)頁面,等接口返回數據後在(zài)進行頁面視圖的(de)更新;另外一種方案是(shì)取消加載中效果,但是(shì)不(bù)做本地(dì / de)數據渲染,而(ér)是(shì)直接給用戶看到(dào)部分靜态頁面。

分包加載

關于(yú)分包加載,就(jiù)老老實實的(de)按照官方文檔做就(jiù)好了(le/liǎo)。進行分包後的(de)效果還是(shì)很不(bù)錯的(de)。具體效果可以(yǐ)參考文章開頭的(de)數據統計。

目前上(shàng)述方案中,效果比較明顯的(de)是(shì)預渲染和(hé / huò)分包加載。一個(gè)是(shì)視覺上(shàng)讓用戶覺得快了(le/liǎo),一個(gè)是(shì)真真切切的(de)把首次加載的(de)資源包變小了(le/liǎo)。

相關案例查看更多