前端系統設計 - 動態牆的非功能需求 (效能)

2026年6月2日

💎 加入 E+ 成長計畫 與超過 1000+ 位工程師一同在社群成長,並獲得更多深度的軟體前後端學習資源

在前端系統設計題目中,動態牆 (feed) 是非常高頻出現的題目之一。動態牆是各類社群媒體的標配,從臉書到推特,再到現在原本以電子報平台起家的 Substack,各個平台都有類似動態牆的機制。

從前端的角度來看,動態牆似乎並沒有什麼特別好設計的,甚至許多前端入門課程,都會練習實作簡易版推特 (Simple Twitter)。

在看這種「功能面看似簡單」的設計主題時,區別資深與否的關鍵點會是非功能需求 (non-functional requirement)。因此這篇文章會聚焦在動態牆前端最重要的效能與可擴展性,可以如何做好相關設計。我們會拆成兩篇文章來談,這篇會專注在效能的設計。

效能 (performance)

對於動態牆來說,最重要的非功能需求莫過於效能。舉例來說,自從推特被收購改成 X 後,外界對產品穩定性與載入體驗的討論變多,在 X 上可以看到非常多對於 X 加載效能的抱怨。當進到網站中需要等四、五秒後才能看到貼文,即使功能沒有壞掉,也會造成使用者的不滿,甚至導致使用者的流失。

在後端系統設計中,有許多討論如何讓貼文更快送到前端的內容;不過除了後端,前端設計上也有許多能夠讓效能加快的地方,以下讓我們逐一討論。

渲染模式選擇

當使用者進到頁面,要看到畫面前,前端會需要先渲染內容出來。先前我們在《前端渲染模式的選擇》一文有談過不同的渲染模式選擇 (如果不熟,推薦先回顧該文後再往下讀)。大家覺得在動態牆這類功能上,應該要用 CSR 還是要用 SSR 來渲染呢?

在 2020 年左右,Meta 曾在《Rebuilding our tech stack for the new Facebook.com》技術文中分享,他們把 2004 年開始 PHP 寫的 SSR,用 React 重構成 CSR 的應用。而在這個遷移的過程,最大的挑戰就是啟動效能 (意即使用者進到網頁後有多快能看到內容)。這是因為 CSR 的做法,會先把 JavaScript 下載到前端後執行才會渲染。

現代的前端 (包含 Meta 旗下的產品) 都會把前端程式碼打包(如果對前端打包不熟,推薦回顧 前端打包工具 (bundler) 是什麼? 為什麼要用? 一文),如果打包產物越大,前端要下載的時間就越長。為了避免這個問題,Meta 團隊透過程式碼分割 (Code Splitting) 把打包產物拆成三個包,第一個是只有極少量的骨架圖包,讓畫面能渲染最基本的骨架。後面的第二個包,才會有實際的動態牆內容 (第三個包則是那些不會在畫面一開始出現的東西,例如要點擊才會展開的選單元件)。

但是後來業界 (包含 Meta 開源的 React) 都逐漸轉向重新探索 SSR,藉此讓使用者一開始能更快拿到內容呈現所需的 HTML。也因此,現在多數的動態牆在網頁前端,目前都逐漸往混合模式的方向走。具體來說,會在最開始使用 SSR 搭配注水 (hydration),後續由 CSR 接管。這是因為對動態牆來說,如果要能夠越快展示內容,SSR 在伺服器端先渲染好再傳給前端會比較快。

舉例來說,先前 Twitter 的官方技術文《Improving performance on twitter.com》 就有談到,Twitter 採用 SSR 的方式在伺服器端就渲染好內容,這樣能加快展示推文給使用者看到。

除了加速展示外,Twitter 團隊選伺服器端渲染的技術決策考量重點之一在於,如果在客戶端渲染,等於渲染的效能不在開發團隊的掌控中;如果使用者用比較舊款的裝置,客戶端的渲染就會花比較多時間。但如果渲染主要發生在伺服器端,團隊至少能在自己可控的基礎設施上優化渲染路徑,而不是完全受限於使用者裝置效能,這樣能確保在渲染這段都能有足夠好的效能。

但如果只輸出 SSR 的 HTML,而沒有後續 JavaScript 接管,貼文雖然能先被看見,卻很難提供現代社群網站需要的即時按讚、留言、分享、展開選單等互動。因此在 SSR 把渲染好的 HTML 傳到前端後,還需要再注水讓網頁能夠互動。由 CSR 接管後,動態牆將能提供高互動性,同時也能支援分頁 (pagination) 等對效能有幫助的方法。

漸進式載入 (progressive loading)

除了透過 SSR 搭配注水,漸進式載入也是在設計上可以協助加快載入速度的方法。所謂的漸進式載入,是指不在一開始就載入所有內容;先載入立即需要的,假如不是立即會顯示在畫面上的就延後載入。這種做法能夠確保最開始載入的量小,藉此讓速度提高。在動態牆的設計上,有好幾個能夠運用上漸進式載入的地方。

首先,前面談到目前業界會採用 SSR 搭配注水的渲染方式,在 SSR 的部分,可以進一步採取串流式 (streaming) 的形式 (我們在《前端渲染模式的選擇》一文中也有介紹,推薦回顧)。事實上,目前 Meta 旗下的社群媒體,動態牆都是採用這種方式。現在進到 facebook.com 的網站中,開啟開發者工具並檢視 Network 分頁,然後點擊 Doc,會能看到進到畫面時拿到的 HTML 檔案。

這時觀察這個 HTML,會發現裡面的內容會不斷增加,因為內容是透過串流的方式不斷送入。具體來說,使用串流式 SSR,可以不用等到所有內容都在伺服器端渲染完成才回傳給前端,而是可以分區塊渲染,每渲染好一區塊就回傳。一般來說,使用者一開始只會先看到最上面的區塊,所以先回傳該區塊,能讓體感的加載速度變快 (對這個實作感興趣,推薦參考 React Conf 的這個演講)。

更進一步說,目前多數的動態牆都會有骨架圖 (skeleton loading) 在還沒有渲染實際貼文前,先把貼文的骨架展示出來(如下方截圖),這會比用載入時常見的旋轉圖示有更好的使用體驗。所以從串流的角度來看,可以在最開始先把渲染好的骨架圖傳給前端來展示,等到實際渲染完貼文後再傳貼文給前端。

這種設計有個需要注意的問題,假如今天使用者的網路速度很快,一開始假如展示骨架圖,然後拿到實際貼文後切換,很可能會出現一閃而過的畫面,這樣使用體驗反而不好。所以一般會搭配時間判斷,在骨架圖的 CSS 中設定透明度,然後只有在例如一定的毫秒數後才會淡入。假如貼文能在這個時間前渲染出來,則不會看到還沒淡入的骨架圖,藉此避免一閃而過的惱人 UX 體驗。

閱讀更多

除了上面提到的點,動態牆的前端還有其他能做效能優化的面向,我們在 E+ 成長計畫中的主題文,有完整的版本。對更深入了解這個主題,以及其他前後端開發、軟體工程、AI 工程主題感興趣的讀者,歡迎加入 E+ 成長計畫一起成長 (連結)。

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們