關注前端早早聊,跟進第三十屆|前端早早聊大會 BFF 專場(GraphQL、統一網關、API 接入管理、超大規模集羣,協議轉換、安全切面、高併發、可視化編排、統一穩定性建設...)8-14 全天直播,9 位講師,點擊報名看直播👉 ):前端
前端早早聊大會,與掘金聯合舉辦。加 codingdreamer 進大會技術羣,贏在新的起跑線, 全部往期都有全程錄播,上手年票一次性解鎖所有web
本文是第十八屆 - 前端早早聊性能優化專場,也是早早聊第 127 場,來自 阿里 飛豬-太吾 的分享。算法
你們好,我是來自飛豬的胡昊,花名是太吾。先不着急開始,由於我剛纔在小助手的朋友圈中看到前幾位導師分享的截圖,同時看到你們的一些問題。有人說我這篇分享在掘金中有對應的文章,相信也有很多小夥伴可能看過那篇文章,我想說的是看到過那篇文章還要不要聽我這邊分享,我以爲仍是要聽的。小程序
文章主要的做用是一個傳播,而一些乾貨確定仍是在 PPT 中,因此你們仍是不要放過前端早早聊 2020 年最後一次分享。前兩位大佬都是比較偏硬核:IDE 和可視化。咱最後又回到了傳統的 H5 上的一個性能優化,可能沒有前兩位那麼硬核,可是但願能夠給你們帶來一些啓發。後端
這個 PPT 也是以前用於咱們集團內的一個分享,因此有點偷懶,其實大部份內容是差很少的,可是有一些對外仍是須要有一些具體的講解。本次分享是《飛豬雙 11 - 基於 Web 的性能優化》,雙 11 我當時的一個職責是性能的 pm,因此對雙 11 總體的 Web 性能優化仍是有必定的理解,但願把這個理解帶給你們。緩存
整個會分爲三個部分來說解。安全
首先是背景。從 Weex 到 Web 是基於什麼樣的考慮?性能優化
咱們飛豬從 2013 年第一個 H5 頁面的落地一直到 2016 年總體切換成 Weex,不管是 Weex 仍是 Rax 總體都是以 Weex 渲染爲主,在飛豬端和手淘端內。一直到 2020 年的 6 月,咱們又總體順應集團的策略又切換回 H5,技術棧也做爲了統一,總體使用了 Rax1.0 的一個技術棧。微信
以前可能有 Rax 的同窗來前端早早聊分享過。咱們怎樣基於這樣一個考慮從 Weex 切換到 H5,咱們對於Weex 性能的可信度仍是比 H5 要好的。但爲何要從一個相對來講好一點的 Weex 技術棧切換到 H5?主要是基於如下幾點考慮:markdown
這是一個總體的背景。
在基於這個背景下,H5 性能確定是比 Weex 性能相對來講要差一點。以前剛切換的 H5 以後,兩次大促(618 大促和國慶),飛豬的會場性能 IOS 大概在 1.5 秒,安卓大概在 2 秒左右。相對比淘系 618 會場的性能 1.4 秒和 2.1 秒,相對來講是差很少的。你們基本上都是把通用的優化手段都用盡了,須要進入一個深水區。對於飛豬雙11 的目標是 IOS 1.2 秒,安卓 1.6 秒,總體是要提高大概 20% 這樣一個水平。在通用手段已經用盡的狀況下,還要提高 20%,這樣也是一個很是大的挑戰。
還有在飛豬這個場景下:
針對這些困難,視野要從前端這邊就是脫離開來,站在是多職能協同的一個方向,主要藉助於客戶端以及服務端的一些能力,來進行一個總體的優化。
總體的一個優化思路,先說一個通用的優化思路:
基於這些通用手段你們都想到了,你們都確定必定都會用完的,而用完以後的效果就好比以前提到的像 61八、國慶大促已是一個頂峯,而以後想再進行優化,就要脫離這些進行更進一步的優化。增進式手段就有如下這些:
主要就是這 4 點來進行一個雙 11 大促的場景的保障。
總體思路用渲染流程來看,塊條對應上面的渲染流程能夠精簡的部分。能夠看到從上到下 SSR、Snapshop 和預渲染效果會愈來愈好,可是它適用的場景確定也是愈來愈少的。這個以後具體會提到。相似一些客戶端預加載、資源的離線緩存、數據的變形請求和模塊的緩存,這都是一些通用的手段,是跟客戶端集成已經用了好久了。
總體的主要思路,以前也說到的就是壓力轉移,把客戶端的壓力轉化到服務端上去。一些緩存、依賴於客戶端的能力、階段的變形以及最後在對用戶進行一些體感上的優化,給用戶最優秀的體驗。
首先說一下預渲染。以前講師也提到預加載,可能飛豬這邊作的更激進一點,能夠先看一下右邊這個效果。左邊開啓預渲染以後,點擊就相似主會場這樣一個膠囊,跳轉過去基本上秒開,沒有任何渲染的過程那種感受。而右邊未開啓預渲染就會有白屏、Loading 以及模塊的加載這樣一個過程,很明顯的一個對比。
什麼是預渲染?客戶端以「離屏」的方式來初始化好容器並 LoadUrl,在上屏以前就完成了頁面的 Rasterization(光柵化)。即客戶端直接把 URL 經過 Webview 在後臺 Load 好,等咱們須要的時候,它直接把 Webview 進行一個上屏的操做就行了,因此作的是比較激進一點。可是爲了是對於主會場這種重點保障,仍是在端側這邊作了這樣一個能力,體驗是比較好。
預渲染它有什麼特色?
可是這樣一個預渲染方案上了以後,FCP(首屏首次渲染時間)就從 1~2 秒,一直到了前端這邊的 100 毫秒,在客戶端那邊的打點基本上在 50~60 毫秒,就能夠完成一個頁面的展現,至關之快。
總體的一個方案的設計,咱們會有一個相似 Orange 這樣一個動態下發的平臺,去配置一些咱們想要預渲染的一個URL,它就會動態下發到一個用戶的 APP 上,APP 獲取到這些配置以後,就會在後臺這邊去加載這樣一個 URL,而且解析頁面,完成頁面的光柵化以後,置入緩存池,咱們還會啓動一個內存預警的監控,保障 APP 的運行穩定,若是有 crash 風險,咱們會自動釋放緩存池中頁面,咱們確定仍是保穩定性爲主,設計了這樣一個內存管控。
當用戶真實的去訪問 H5 頁面的時候,咱們會檢測用戶 是否命中了預渲染的 URL 配置。咱們會有一個 URL域名,以及 URL query 的一些特殊化的參數,進行 key 的對比。若是命中了以後,就會經過 URL 做爲 key,在緩存池中找到 Webview,直接進行一個上屏的操做,GPU 直接進行上屏的顯示。由於用客戶端在後臺已經渲染好這個頁面確定跟前端的一些邏輯不相符合,因此咱們須要在真實的上屏以後,客戶端會派發一個 document 事件來通知 H5 頁面渲染完成以後,前端監聽這個事件以後,咱們會進行一些對於性能埋點的處理、頁面埋點的處理以及最後那些動態投放的一些事件的處理,這些都是在前端須要進行兼容的地方。
作完這些以後,這一個頁面的總體展現邏輯就完成了。在用戶退出這個頁面以後,咱們會清除對應的 Webview 緩存,而且在 300 毫秒後馬上又在後臺從新去啓動這樣一個新的 Webview 去加載這個頁面,從新的去進行下一次的這樣一個總體流程。
預渲染這樣一個方案比預加載只加載一個 Webview 容器,不去請求真實的數據,可能會更加激進一點。可是效果也會相對來講更好一點。
第二個方案就是 SSR。重啓 SSR 是爲了什麼?通常如今在集團內基本上 SSR 它的定義,從本來的 Server-side-render 慢慢轉移到 Serverless-side-render,順應 Serverless 這樣一個大潮,反正慢慢的發現 SSR 可用武之地。咱們這種不是傳統意義上的 SSR,跟傳統意義上 SSR 就是相似 PC 時代這種主文檔,就直接返回HTML主文檔的那種 SSR。
咱們不一樣的點是看底下這樣兩個渲染流程的對比,上面就是傳統的 CSR 的渲染流程,在藉助客戶端的文檔緩存以及數據的預加載,以後就進行模塊的 JS 和渲染模塊。而咱們這邊,經過這個圖你們能夠看到咱們的 SSR 是在接口中返回的 HTML,在接口返回 HTML 後,咱們去把 HTML 再異步 hydrate 到頁面上去,咱們至關因而省掉了後面加載模塊 JS 和渲染模塊這樣一個流程,由於把 HTML 放在接口中返回,因此接口多是會比日常會更慢一點。咱們認爲把 HTML 直接塞到頁面中去,大概會花 10 毫秒左右的時間。這樣,總體在減掉後面模塊JS 加載和渲染模塊的時間,咱們這邊大概會節省 700 毫秒~800 毫秒的時間,SSR 相對於 CSR 這樣一個對比。
整個渲染流程的改變,爲何是基於這樣一個考慮,而不是把在傳統意義上在主文當中直接返回整個頁面的結構,而是在接口返回的時候,返回這樣一個 HTML 來再進行一個渲染。
這背後的思考主要是基於這樣一個考慮:以前手淘那邊也作了這樣一個方案,他們當時作了同步 SSR 放在主文檔中返回。他們當時就發現有同步 SSR 後,一個是白屏時間會變得長,由於它沒法使用客戶端的一些能力,例如離線包以及數據預加載這樣兩個客戶端提供了很好的一個能力。咱們就跟進了異步 SSR方案,也就是放在接口中返回一個 HTML 這樣一個方式。
它有幾個優勢:
咱們基於改形成本最小化的這樣一個原則:
完成這些考慮以後,咱們就成功地上了 SSR 方案,也獲得了不錯的效果,基本上是從以前的 1~2 秒用了 SSR 以後基本上平均耗時能夠降到 1 秒如下。
頁面快照。先看右邊的效果,開啓了 Snapshot 以後,就沒有 Loading 的環節,直接點開頁面,頁面就直接進行一個相似直出的效果。Snapshot 實際上的效果確定是比 SSR 要好的,可是咱們有了 Snapshot 爲何還要 SSR?
針對這個頁面快照,咱們這邊是設計了兩種方案。一種方案是接口緩存,一種方案是傳統意義上的 HTML 緩存。爲何會有這兩種方案的並存?
一種會場天天都會變陣,其實你看雙11或者雙12,你去逛會場,天天模塊的順序以及模塊的數據展現邏輯,運營天天都會去進行修改的。因此天天都會變的狀況下,若是是採用了 HTML 緩存,就不可避免的帶來一些閃動的問題。例如你昨天訪問了這個頁面,今天再訪問這個頁面,它可能中間有幾個模塊沒有了,或者有幾個商品,它的坑位從 4 個變成了 6 個,這樣你進去以後,它整個頁面都會啪啪啪亂閃一氣,而且就這種閃動過程,它其實會可能會帶來不少毛病,一些不可預知的問題。例如就是模塊可能會重複的渲染,而且有些模塊它可能就會錯位這樣一個特別玄學的一些問題。
因此咱們又設計了第二個接口緩存的一個方式,接口緩存配合上模塊緩存,基本上也能夠作到性能和直接 HTML 緩存這樣性能保持基本一致。由於接口緩存配合模塊緩存數據相對來講固定,就避免了閃動,而且咱們爲什麼有並存這樣一個東西,咱們會發現 HTML 緩存也並不是毫無用武之地,就相似右邊這種場景,所有會場這種場景,他在整個大促期間基本上是不會變更的。因此就採用 HTML 緩存帶來更高更快的一個加載效率,是可使用 HTML 緩存。
整個的方案設計以下:
再提兩點,一些設計上的思路:
最後一點就是 SPA。咱們慢慢的在頁面中的一些優化,給用戶的體驗也很好了。可是頁面間的一個切換的體驗還不是很好。由於以前其實你看到底下是有 Tabbar。可是它實際上是多個頁面,你若是像以前那種方式去切換底部的 Tab,其實它整個是一個頁面的跳轉,是 replace 方式,整個頁面都會進行一個刷新,這樣體驗是很是很差的。
在雙 11 的時候,咱們對它進行了一個改進。底部 bar 是總體一個包框,咱們經過點擊底部 bar 切換的時候,咱們僅須要去獲取數據。仍是剛纔提到那個點,咱們的頁面是經過數據進行獲取到模塊,經過模塊拼裝組成的。因此咱們只須要知道模塊有哪些,咱們就能夠把頁面組成起來。因此咱們切換 tab 的時候,咱們只須要去獲取數據,去獲取到模塊,把頁面的 DOM 替換一下,咱們就能夠完成到頁面的這樣一個切換,而不用整個的 replace。
爲何基於 SPA 實現,仍是剛纔說到那個點。
咱們初版設計開啓了 SPA 以後,咱們就獲取那個模塊的數據,替換當前 tab 對應的模塊,進行頁面的更新。可是咱們發現這樣有一個問題:若是總體去不停的去替換模塊,仍是比較卡頓的。相對於直接傳統意義上咱們心目中那種單頁應用仍是有一點鴻溝,因此咱們就對它進行了升級。
咱們只緩存首屏的 DOM,減小數據獲取的過程。而且在高端機上咱們會請求首個 tab 數據渲染完成以後,咱們會去預加載其餘幾個 tab 的數據。這樣下次切換過去的時候就沒有數據獲取過程,咱們能夠直接取用它。就至關於把多頁面之間的數據同時都拿到以後,咱們切 tab 就能夠造成絲滑般的切換效果。咱們只須要隱藏其餘 Tab 容器內 DOM。把該展現的那些 DOM 給 display 出來就行了。
最後再提兩個小點,以前講師他們也說到。基本上每一個優化都要藉助客戶端離線能力,離線包和數據的並行請求,我看基本上是 H5 這邊是每次都會用到的。
可是就說一點小的設計,咱們對於會場頁面是設計了一個 **URL + package **方式,咱們會在信鴿,就是咱們一個後臺去輸入須要進行離線的頁面,在會場這種場景下。咱們信鴿就會在後臺跑一個 puppetter,把頁面的資源給獲取到,而且再經過一些滾屏的操做,把一些懶加載的資源也給獲取到。就把整個資源打成一個資源包,最後經過一個hash的方式,在去真實頁面訪問的時候,進行匹配。
第二點,數據並行請求的這樣一個部分,咱們設計了相對於正常的 Memory 命中和 Miss 不命中這樣一個狀態下,咱們還設計了一個 Ongoing 這樣一個狀態。咱們認爲只要客戶端發起請求,那必定是比前端真實發起請求要快的要提早的,由於實際它確定是要提早的,因此咱們就會等待就是客戶端真實的請求返回以後,咱們再會拿客戶端的那樣一個數據,而不是從新發起一次請求。
整個這邊就不那麼細說了,反正最終達成了咱們當時這樣一個目標,基於咱們以前說到的不管是通用手段也好,仍是一些增進手段也好。通用手段可能也是提供了很大的一個幫助,增進手段在它的基礎上有個更高的一個提高。反正最終是達成這樣一個目標,而且有了這些東西以後,咱們會有一些將來可期的這樣一種感受。
性能優化,慢慢的就會發現它從前端的這樣一個職能慢慢的上升到多職能協同的這樣一種方式。慢慢你若是去優化,你確定就慢慢不能站在前端的這樣一個視角,慢慢的就會依賴於就相似前面說的 NSR 還有服務端這種 SSR 以及咱們如今還有那種 ESR 就是 CDN 邊緣計算這樣去的一些就是東西,就慢慢你會發現性能優化慢慢是超脫了前端這樣一個單純的職能這樣一個方面,你要站在多智能協同方式進行性能優化的嘗試。
規劃就不那麼細說提幾點:
這樣等等一系列的內功提高,以及咱們飛豬這邊目標是前端的兩秒達標率要達到 90%。因此單純的單業務,咱們端內的單業務固然就須要去拓展到多業務。咱們就想法是有一個優化手段及如今在集團內咱們是有跨端性能小組是有白皮書這樣一個方式,去記錄一些優化手段,慢慢去 push 各個業務,進行落地,而且去收集各個業務的一些好的優化的手段,來進行沉澱反哺,慢慢去把總體的性能給提升起來。
最後慣例推薦一本書,這邊推薦的就是《金字塔原理》,它是講一個相似寫 PPT 或者是思考表達和解決方式的這樣一種邏輯。寫 PPT、寫文章之類的這樣一種邏輯,是一套就是邏輯清晰、重點突出、井井有條,簡單易懂的思考表達方式和規範動做。這本書我以爲是挺好的。看了以後對於作 PPT 或者是寫文章,都是由很多的幫助的。你們有興趣的能夠去看一下。
最後慣例中的慣例,確定是須要招人的。咱們團隊關因而飛豬的用戶前端和數字化經營團隊,咱們的業務是關於旅遊的一切咱們均可以去嘗試。咱們團隊的基礎事項。以前有咱們團隊的南路,也來分享過 Web Flutter 這樣一個方案,咱們團隊的有 Flutter,那麼以及在咱們如今 SSR 也是咱們團隊基於 Serverless 這樣一個大潮去作的。還有一些中後臺的微前端,以及一體化的開發以及端線互動,以及智能搭建這樣一個東西,咱們團隊技術思想都是包括的。 因此基本上各個方面你們都有包括,因此你們有興趣就等你了,就能夠經過郵箱,P六、P7 多多益善。
你們也能夠關注一下咱們飛豬技術的公衆號,Fliggy F2E 以及掘金,有些以前看到我這篇文章有在掘金上發,也是被咱們飛豬前端這邊專欄去收藏。若是對跨端這邊性能這邊有想法的,也能夠加我微信瞭解一下。
關注前端早早聊,跟進學習更多 BFF/GraphQL,請關注第三十屆|前端早早聊大會 BFF 專場 - 玩轉先後端接口(GraphQL、統一網關、API 接入、API 管理、協議轉換、統一安全切面、高併發處理、可視化編排、統一穩定性建設...)8-14 全天直播,9 位講師,報名上車看直播👉 ):