從 “卡頓” 到 “秒開”:外投首屏性能優化的六個實戰錦囊
一、背景
在互聯網時代,網站性能的好壞直接影響用戶體驗和轉化率。對投放的廣告頁面而言,如何在保證視覺效果和功能的同時提升加載速度,成為了開發者必須面對的挑戰。
本文將探討幾種有效的外投頁面性能優化策略,包括構建方式的優化、非首屏組件的處理、關鍵大圖的預載、動效方面的升級,以及針對弱網環境下的降級策略、外投流渲染的技術升級等相關內容。
二、難點 & 收益
首屏秒開率口徑嚴格
首屏秒開率通常指用戶從觸發頁面加載(如點擊廣告鏈接)開始,到首屏內容完全渲染完成,并可進行交互所花費的時間在 1 秒以內的比例。其中,“首屏內容” 指用戶設備屏幕可見區域內的全部內容,包括文字、圖片、按鈕等關鍵信息元素。
“完全渲染完成” 不僅要求視覺上顯示完整,還需保證頁面元素的布局穩定,不存在閃爍、錯位等情況;“可交互” 則意味著用戶能夠對首屏內的交互元素(如按鈕、輸入框)進行有效操作,不會出現點擊無響應的情況。
投放環境復雜
外投頁面的投放環境極為復雜。用戶可能分布在不同網絡環境中,包括 4G、5G、Wi-Fi 甚至弱網或不穩定網絡環境,在 2G、3G 等低速網絡或信號波動較大的區域,數據傳輸速率受限,資源加載容易出現延遲。而且,用戶使用的設備性能差異懸殊,從高端旗艦機到中低端老舊設備,硬件配置的不同會導致頁面解析、渲染能力參差不齊,部分低端設備難以快速處理復雜的頁面代碼和資源。
頁面收益
經過長達兩個季度的性能優化專項工作,外投頁面取得了顯著的收益:
- 外投頁面曝光率提高了10%左右
- 首屏秒開率從15%提高到65%左右
三、外投頁面的渲染策略
在構建現代 web 應用時,SSR(Server-Side Rendering)是常用的渲染方式,但我們外投頁面大部分頁面采用的是ISR,字面上理解,可以理解為SSR+SSG。可以參考下面這張圖。
在初次構建時,ISR 會像 SSG 一樣預生成靜態頁面,并將其部署到服務器或 CDN。
當用戶訪問頁面時,若頁面已經過期,ISR 會觸發一個后臺再生成過程。這個過程在服務器端完成,類似于 SSR,但與 SSR 不同的是,再生成的頁面會被存儲為靜態文件,而非每次請求都進行實時渲染。
具體再生流程
- 用戶請求過期的頁面時,ISR 會啟動一個后臺再生成過程。
- 服務器重新生成頁面,并將新的 HTML 文件更新到緩存中。
- 在生成過程完成后,下一個用戶請求將會獲得更新后的頁面。
舉個例子,假設一個 Next.js 頁面設置了 revalidate 選項為 10 秒,這意味著頁面在構建時將會生成靜態 HTML 文件,并在 10 秒內保持不變。
具體流程
- 0-10 秒:在初始構建完成后的前 10 秒內,用戶請求的 HTML 文件都是之前生成的靜態頁面。頁面不會重新生成,所有請求都直接返回緩存的靜態頁面。
- 10 秒后:當第一個請求到達并發現頁面已經過期時(超過了 10 秒),ISR 會啟動一個后臺再生成過程。此時,服務器仍然會返回舊的緩存頁面給用戶,同時在后臺生成新的頁面。
- 生成完成后:當后臺生成的頁面完成后,下一個用戶請求將會得到新的頁面。新生成的頁面會被存儲為緩存靜態文件,并在后續的 10 秒內繼續使用,直到再次觸發再生成過程。
這種機制保證了頁面在大部分時間內快速響應,同時能夠在后臺靜默地更新內容,確保用戶能盡快看到最新的數據。
外投主要是幾個固定頁面,此處作如下分類。
分類
- 交互性交強的頁面, 如盲盒這類頁面的特點,放量占比流量大,首屏秒開受動效影響較大,一般配置完運營就短期內不會進行更新,適合ISR。頁面靜態內容為主。
- 容器頁面用于進行效果AB測試的頁面,不太適合用ISR,在構建時獲取AB的結果, 實時性要求較高,AB的結果因人而異,采用SSR策略。
- 變更比較頻繁的頁面,不接受短時間的差異的,這種一般采取SSR策略。
不足:使用ISG構建的頁面, 在于客戶端和客戶端建聯的時候,需要等待HTML文檔全部下載完成,瀏覽器才開始渲染,所以ISG構建的頁面 TTFB 都會比較大。若一個網頁的TTFB 較慢,后續的FMP、LCP、FCP 等所有指標都會很難提高, 所以在此基礎上,我們在Q1啟動了外投落地頁的流渲染的技術架構升級,具體會在本篇文章的第四段詳細介紹。
四、組件懶加載
在優化頁面加載時,非首屏組件的渲染方式至關重要。比如頁面的挽留彈窗,頁面的二級彈窗,這些都屬于非首屏的內容。 可通過組件的封裝和抽取,區分首屏組件和首屏組件,哪些需要直出dom,哪些無需直出dom,可以在客戶端在進行渲染,這里 通過使用 Next.js的 next/dynamic 實現組件的動態加載,可以將這些非首屏組件的 SSR 設置為 false ,在用戶點擊到了到相應位置時再進行加載。這種懶加載策略最直接影響的首屏的bundle(js、css),追求極致的首屏體積。
const DyamicMarqueeTop = dynamic(() => import('./marqueTop'), {
ssr: false,
loading: () => <div></div>,
})
const DyamicDialog = dynamic(() => import('./dialog'), {
ssr: false,
loading: () => <div></div>,
})
下面是優化前后的外投H5頁面對比, 大圖模板 預計減少5.3kB。
商品流模板
五、圖片preload策略
對于外投頁面而言,影響首屏秒開的有的是一些關鍵性大圖。為了提升大圖的加載效率,可以在 HTML 的 <head> 中使用 <link rel="preload"> 標簽提前加載關鍵大圖。這種做法能夠在用戶訪問頁面時,優先加載重要的視覺元素,從而減少用戶等待時間。
import Head from 'next/head'
/** 單品圖模板自定義的頭的一些 業務邏輯 */
export const ScratchHead = () => {
const defaultUrl = 'xx'
const scratchInfo = global?.componentList?.find((item: { name: string }) => item.name === 'scratchCard')
const bg = scratchInfo?.props?.bgImg || defaultUrl
return (
<>
<Head>
<link rel="preload" href={`${bg}?x-oss-process=image/format,webp/resize,w_750`} as="image" />
</Head>
</>
)
}
六、外投動畫升級
現狀
由于盲盒玩法,流量波動比較大,優化盲盒玩法的首屏秒開優先級較高。
結合apm上報的路徑,這是一個canvas容器。
html.support-webp > body > div#__next > div > div > div > canvas
初步定位為,需要頁面的動畫渲染影響了整體秒開,于是我們推動產品和設計同學 進行動畫升級從現有的apng升級到lottie。
75分位的首屏秒開 從 4.8s 多下降到 1.8s 左右, 首屏秒開提升16pp左右。
為什么升級一個動效,就對頁面的秒開影響之大?
apng
在沒全量應用lottie之前,外投針對復雜動畫的處理一直都是apng,可以說是苦apng久已。
- apng的缺點在于資源體積非常大,一般的動畫都得達到2-4M, 光資源加載就要好幾秒了,何談首屏秒開。
- 由于apng有瀏覽器兼容性問題,對于apng資源的播放我們都是將apng解碼,然后每一幀的圖片用canvas 畫布進行渲染。
- 由于動畫的容器是canvas,無法首屏直出dom,只能等到客戶端場景下載JS,加載資源后再進行渲染, 這就是含有動畫模板秒開比較低的本質原因。
(下面的流程圖均是cursor結合excalidraw自動生成出的)
染apng具體流程
lottie
為了解決上訴問題, 我們第一時間想到了lottie 動畫, 對于首屏關鍵的動畫從apng 直接轉到lottie。
lottie的文件體積通常較小,因為它是以 JSON 數據的形式存儲動畫信息,而非實際的圖像幀。對于復雜的動畫,尤其是包含大量圖形元素和動畫效果的情況,Lottie 的文件大小優勢更為明顯。可以看下面對比圖:
同樣一個動畫播放, apng 需要將近2M多,但是lottie需要的資源僅僅需要幾百k,資源體積下降十分明顯。
設計師通常給到的lottie資源是這樣的:
開發往往需要對設計師給到的lottie文件進行cdn 化處理:
第一步: 需要壓縮圖片資源,然后上傳到OSS。
第二步: 然后替換json 中的 assests 路徑。
第三步: 上傳lottie.json,生成一個url,供我們前端進行渲染。
對于這些復雜的操作,我們已經內置為一個npm 包@dw/lottie-cli,專門用于處理設計師給的lottie資源,同時封裝了基于react的lottie組件。
- lottie-cli支持 tinify圖片壓縮
- 支持webp生成
- lottie-player 支持 webp 渲染
lottie的缺點,在于依賴一個lottie-web的運行時,以及lottie.json 資源的大小,至于方案如何選擇,還是要具體業務具體分析。沒有完美的方案,找到適合當前頁面的動效才是最好的。
減少runtime體積
lottie動畫依賴的lottie-web沒法做到tree-shaking,因此修改外投引入lottie的方式。將lottie js 體積包拆分成 svg、html、canvas. 三種渲染依賴JS ,將運行時體積從80kb降低到40kb,首屏秒開預計提升100ms。
優化前
優化后
針對lottie動畫SSR場景下沒法直出dom的情況,新增lottie動畫預渲染骨架。在SSR場景,用動畫的第一幀dom,作為lottie動畫的骨架(只適用于lottie渲染模式 是用svg 或者是html,canvas模式不支持 ),首屏秒開提升100ms。
優化前
優化后
七、低端機和弱網優化
為保障所有用戶都能收獲良好使用體驗,在這個過程中,尤其需要關注那些使用低端機器的用戶群體。針對這部分用戶,我們可制定相應的降級策略,比如跳過動畫展示環節。具體實施時,通過對用戶設備性能進行檢測,以此來決定是否加載動畫元素,進而確保頁面在性能相對較低的設備上也能夠保持流暢運行。
弱網指標判斷
弱網的初步定義
當網絡的往返時間(RT)大于 150ms 時,便認定其處于弱網狀態。
網絡性能檢測方法
針對同一張小體積圖片,在每次訪問時都對其進行訪問操作,并計算相應的往返時間(RT)。我們將該 RT 值作為此次訪問網絡性能的代表指標,通常情況下,RT 值越短,則意味著網絡性能越佳。
低端機指標判斷
核心判定邏輯
綜合考量去navigator上的 deviceMemory、hardwareConcurrency、saveData 以及顯示屏幕、觸摸屏幕等方面的信息,以此構成判斷低端機的初步標準。
具體判定細則
- 內存方面:若 deviceMemory 的值小于等于 2GB,那么可直接判定該設備為低端設備。
- CPU 方面:當 navigator.hardwareConcurrency 的數值小于 4 時,同樣能夠直接判定此設備屬于低端設備范疇。
- 設備像素方面:倘若設備像素低于 600,那么該設備可被判定為極端設備。
卡頓指標判斷
卡頓指標的檢測邏輯
針對卡頓指標的檢測,我們采取如下方式:通過創建一批div元素,并為其施加動畫效果,以此來測試設備的性能表現,隨后給當前設備進行打分,最終依據分數的高低來區分不同性能的機器。具體的卡頓判定標準如下:
- 若渲染時間大于 60ms,這種情況可被視作存在發生卡頓的可能性。
- 而一旦渲染時間超過 200ms,那么就認定該設備出現了嚴重卡頓的情況。
收集到上述指標后,最終落地到頁面就是動畫跳過,或者是動畫降級,從動畫變成一張靜態圖,或者是在不阻塞主流程的情況下, 走下一步跳過動畫。
偽代碼如下:
// 是低端機或者是弱網設備
if (isLowEndDevice || isLowNetWork) {
// 跳過動畫
} else {
// 加載動畫
}
降級策略
移動端設備,針對我們外投頁面而言,影響比較大的兩個因素:
- 弱網
- 設備性能
安卓設備性能小于IOS 設備,安卓設備解析JS的時間長,在弱網的情況下,用戶加載JS的時間比較長。
Lotttie動畫降級
a. 主要是針對lottie 文件的assets 圖資源進行降級。
b. 針對低端機型直接跳過動畫,直接使用lottie預構建的骨架, 保證SSR的dom直出。
動畫降級方案
目前外投播放apng 動畫的流程涉及到如:
一個apng的動畫的播放生命周期,涉及到資源拉取時間 + 解析apng 的時間,但是這對于性能較差的低端機來說,可能是在災難。這里直接如果識別到是低端機,直接跳過動畫。如果在3秒內沒有加載完成,可以直接進行兜底超時邏輯,展示兜底靜態圖。
輪播圖降級方案
針對低端機和弱網首屏引入的swiper.js,這里直接去掉swiper,使用css 手寫無限輪播動畫。
通過上面的優化動作,針對低端機或者是弱網設備,我們的頁面也能夠快速的打開。
八、流渲染技術架構升級
經歷過上面一些常規性的優化,想要首屏秒開進一步提高,需要整體框架層面進行架構升級。 我們針對外投大流量頁面進行了流渲染的架構遷移。
流渲染的優勢
- 渲染將頁面拆解為多個可獨立渲染的 “片段”(Fragment),服務端逐段生成 HTML 并流式傳輸給客戶端。例如,先返回頭部和主體框架,再逐步填充內容模塊(如導航欄、列表項等)。
- 用戶體驗優化:用戶無需等待整個頁面生成即可看到部分內容,尤其是關鍵信息(如標題、首屏圖文)的展示時間顯著縮短,提升 “感知速度”。
- 性能數據對比:在復雜頁面中,流渲染可使首屏渲染時間(TTFB)減少 30%~50%,尤其適用于數據分批次加載的場景(如瀑布流、分頁內容)。
- 流渲染的分階段交互激活:流渲染可將頁面拆解為多個 “可交互單元”,服務端在傳輸片段時,同步或異步注入對應的客戶端邏輯。
例如:先渲染商品列表的靜態結構,同時加載列表項的點擊事件邏輯,使首屏內容在 hydration 完成前即可部分交互。結合增量 hydration(Incremental Hydration),僅對動態更新的片段進行交互激活,減少整體腳本執行時間。提升頁面的 “可交互時間”(TTI,Time to Interactive),使用戶更早能與頁面互動。
歷史流量遷移
在流渲染遷移過程中,外投鏈接完成從非流渲染到流渲染的升級。
具體實施策略
- 新增頁面:直接使用新鏈接,原生支持流渲染技術,享受性能優化紅利。
- 存量廣告計劃兼容:
- 已發布且無法修改鏈接的計劃:通過代理轉發機制,將原鏈接(cdn 域名)的請求回源到流渲染服務,實現 “鏈接不變、內容由流渲染承載” 的無感知遷移。
- 未發布的非流渲染鏈接計劃:聯合后端與產品團隊,通過數據批量處理(刷數),將原鏈接批量替換為流渲染鏈接,確保新計劃直接使用高性能架構。
具體的架構圖參考如下
apm性能腳本內嵌
在流渲染頁面外投場景中,雖已實現部分頁面流渲染,但首屏秒開指標提升效果不佳。通過對大盤數據深入剖析,發現接口響應時間(RT)75 分位值約為 50ms,首字節時間(TTFB)75 分位值約為 500ms,由此可判斷服務端性能并非瓶頸所在。將分析方向轉向客戶端后,確認首屏秒開的關鍵制約因素并非框架本身,而是監控 SDK 腳本加載耗時。
具體而言,頁面首次有效繪制(FMP)的計算依賴于外部腳本 xxx.js。當前機制下,頁面渲染時異步加載 xx.js,需等待該腳本加載完成后才能進行 FMP 標記計算,這導致 xx.js 加載耗時直接計入 FMP 統計。考慮到 xx.js 體積達 35KB,在首屏階段異步加載此腳本,對網絡條件較差的外投頁面性能影響顯著。
針對外投弱網場景,和APM團隊提出首屏先采集后上報的需求,最終APM 團隊提供了 7KB 的性能內聯版本 SDK。在流渲染的的白屏階段同步加載 性能腳本JS,經實踐驗證,優化效果顯著:在 4G 網絡環境下,FMP 指標從優化前的 1000ms 降至 500ms 左右,首屏秒開率提升約 25 個百分點,提升十分顯著。
九、總結
在頁面的性能優化過程中,結合流渲染的技術架構升級、ISR、動態加載非首屏組件、關鍵大圖預加載、Lottie 動畫,以及針對低端設備的降級策略,可以形成一個多層次的優化方案,為用戶提供流暢而快速的訪問體驗。
通過這些優化措施,外投頁面不僅能夠更好地滿足用戶需求,還能有效提高轉化率,為業務帶來更多機會。希望本文能夠幫助你在實際項目中更好地應用這些性能優化策略。