喂!我是 Wei

Front-End Engineer

Be a Problem Solver.

⌘K

導覽

所有文章緣起互動小功能

文章分類

目錄
先不要急著優化,先確認卡在哪第一層:不要一次 render 5000 筆第二層:分頁或 infinite scroll第三層:降低每次 render 的計算成本第四層:避免 row 不必要重 render圖片、欄位和互動也要看實際效能優化案例可以怎麼講?SituationTaskActionResult面試回答模板

相關文章

前端工程師面試題:useMemo 和 useCallback 差在哪?什麼時候不該用?

2026年6月4日

前端工程師面試題:後端 API 回應很慢,你會怎麼協助排查?

2026年5月30日

前端 CI/CD 與正式環境除錯:從 Pull Request 到事故排查

2026年6月24日

最新文章
全部 →
前端 CI/CD 與正式環境除錯:從 Pull Request 到事故排查
2026-06-24
即時資料怎麼選?Polling、SSE、WebSocket 比較
2026-06-23
前端系統設計:如何拆元件、資料流與大型專案架構?
2026-06-22
無障礙不是加 ARIA:語意化 HTML、鍵盤操作與焦點管理
2026-06-21
CSS 與 RWD 面試整理:Flexbox、Grid、定位與層疊脈絡
2026-06-19
← 返回文章列表

前端工程師面試題:5000 筆列表卡頓,你會怎麼優化?

2026年6月6日·約 6 分鐘閱讀·
前端面試系列效能優化大量列表

面試問「如果列表頁一次載入 5000 筆資料,頁面開始卡頓,你會怎麼優化?」其實不是在問你會不會背 useMemo。

它真正想看的是:

  • 你會不會先量測瓶頸
  • 你知不知道 DOM 數量會影響渲染
  • 你能不能把資料量、渲染量、互動頻率分開處理
  • 你有沒有實際做過效能優化的判斷順序

5000 筆列表卡頓的優化順序


先不要急著優化,先確認卡在哪

我會先用工具確認瓶頸:

  • Chrome Performance:看 scripting、rendering、painting 哪一段最長
  • React DevTools Profiler:看哪些 component 一直 re-render
  • Network:確認是不是 API 慢、payload 太大
  • Lighthouse / Web Vitals:看 LCP、INP 是否受影響

面試可以這樣回答:

我會先量測,不會一開始就猜。因為卡頓可能來自 DOM 太多、資料處理太重、API payload 太大、圖片太多,或是每次輸入都觸發整個列表重 render。先用 Performance 和 React Profiler 找出主要瓶頸,再決定優化方向。


第一層:不要一次 render 5000 筆

如果畫面上只看得到 20 筆,就沒有必要同時 render 5000 個 row。

最常見解法是 virtualized list。

概念是:

資料有 5000 筆
畫面只顯示目前 viewport 附近的 30 筆
使用者 scroll 時再替換可見區塊

React 常見套件:

  • react-window
  • react-virtualized
  • @tanstack/react-virtual

面試回答:

如果瓶頸是 DOM 節點太多,我會優先做 virtualization,讓畫面只渲染可視範圍內的 row。這通常比單純加 memo 更有效,因為它直接減少 DOM 數量和 layout / paint 成本。


第二層:分頁或 infinite scroll

如果 5000 筆資料其實不需要一次拿回來,可以從產品和 API 設計處理。

常見方式:

  • pagination:一次載入 50 或 100 筆
  • infinite scroll:接近底部再載入下一頁
  • server-side filter / sort:搜尋、排序交給後端處理
  • cursor pagination:避免 offset 很大時 DB 查詢變慢

如果使用者不可能同時需要 5000 筆,前端硬吃全部資料通常不是好設計。


第三層:降低每次 render 的計算成本

假設資料已經拿回來,但每次 state 改變都重新 filter / sort 5000 筆,就會很容易卡。

可以用 useMemo memoize 衍生資料:

const visibleItems = useMemo(() => {
  return items
    .filter((item) => item.name.includes(keyword))
    .sort((a, b) => a.createdAt.localeCompare(b.createdAt));
}, [items, keyword]);

但要注意:

useMemo 只能避免 dependency 沒變時重算,它不能解決「資料本身太多」或「DOM 太多」的問題。

如果 keyword 每打一個字都會變,還可以搭配 debounce:

const deferredKeyword = useDeferredValue(keyword);

或自己做 debounce,避免每個 key stroke 都立刻觸發昂貴計算。


第四層:避免 row 不必要重 render

如果每個 row 都是複雜元件,可以考慮:

  • React.memo(Row)
  • 穩定 callback reference
  • 避免 inline object / inline function 傳進 memo child
  • selector 只取需要的狀態

範例:

const Row = memo(function Row({
  item,
  onSelect,
}: {
  item: Item;
  onSelect: (id: string) => void;
}) {
  return <button onClick={() => onSelect(item.id)}>{item.name}</button>;
});

如果 onSelect 每次 render 都變,Row 還是可能重 render:

const handleSelect = useCallback((id: string) => {
  setSelectedId(id);
}, []);

圖片、欄位和互動也要看

有時候卡頓不只是 row 數量,而是每個 row 太重。

可以檢查:

  • 每列是否載入圖片
  • 圖片是否有 lazy loading
  • 是否用了太多 box-shadow / blur / sticky
  • hover 時是否觸發大量 layout
  • 是否有大量 tooltip / popover 同時 mount
  • 每個 row 是否都建立複雜 formatter

前端效能常常不是單點問題,而是很多小成本疊在一起。


實際效能優化案例可以怎麼講?

如果面試問「請說明你實際做過的一次效能優化案例」,可以用 STAR 結構:

Situation

某個管理後台列表頁資料量變大後,搜尋與切換 filter 明顯卡頓。

Task

目標是讓列表互動恢復順暢,並降低初始載入時間。

Action

我做了幾件事:

  1. 用 React Profiler 確認 filter 改變時整個列表都重 render
  2. 把一次載入全部資料改成 server-side pagination
  3. 對搜尋輸入加 debounce,避免每次 key stroke 都打 API
  4. row component 加 React.memo
  5. 將昂貴的欄位格式化結果改成 memoized derived data
  6. 圖片加 lazy loading,並限制縮圖尺寸

Result

可以講具體結果:

初始 payload 從 5MB 降到 300KB,列表互動從明顯卡頓變成即時回應,React Profiler 裡單次 filter 操作的 commit time 也明顯下降。

如果沒有真實數字,不要硬編。可以說「我當時用 profiler 比較前後,主要瓶頸從列表重 render 轉移到 API 等待時間」。


面試回答模板

我會先用 Chrome Performance、React Profiler 和 Network 確認瓶頸。若問題是一次 render 5000 個 DOM node,我會優先做 virtualized list;如果資料不需要一次拿完,會改成 pagination 或 infinite scroll,並把 filter / sort 往後端移。前端這邊會用 debounce、useMemo、React.memo、穩定 callback reference 來降低不必要計算和 re-render。最後我會用 profiler 或 Web Vitals 比較優化前後,而不是只憑感覺判斷。

這題的重點是順序:先量測,再減少渲染量,最後才做細部 memoization。

分享:XLinkedIn
← 上一篇前端工程師面試題:MobX、Redux、Zustand 怎麼選?
下一篇 →前端工程師面試題:React Key 為什麼重要?useEffect dependency array 為什麼重要?