학습 공간 개념 · 판단 · 실험

Frontend Performance Lab

프론트엔드 설계

큰 데이터와 적은 DOM: 목록 가상화

데이터가 수만 건이어도 화면에 보이는 행과 주변 몇 개만 실제 DOM으로 그려 렌더링 부담을 줄입니다.

이럴 때 필요해요

데이터 정렬이나 필터 계산을 아무리 빠르게 만들어도, 수만 개의 행을 한꺼번에 브라우저 DOM으로 만들면 화면이 느려지기 때문에 계산과 화면 표시 비용을 나누어 다루어야 합니다.

어떻게 동작하나요?

목록에 항목이 10만 개 있을 때 사용자가 한 화면에서 실제로 보는 행이 20개뿐이라면, 10만 개 태그를 모두 만들어 둘 필요가 없습니다. 스크롤 위치와 화면 높이를 계산해 지금 보이는 구간과 위아래 여유분(overscan)만 실제 DOM에 유지하는 기법을 목록 가상화(Virtualization 또는 Windowing)라고 합니다.

Web Worker는 무거운 데이터 계산을 다른 스레드로 옮겨 주지만 페이지의 DOM을 대신 그려 주지는 못합니다. React의 메모이제이션(memo, useMemo) 역시 처음부터 수만 개의 DOM 노드를 화면에 마운트하는 비용 자체를 없애 주지 않습니다. 따라서 성능 분석 도구에서 계산이 느린지, DOM 생성과 배치(Layout)가 느린지 먼저 구분한 뒤 표시할 행 수를 줄여야 합니다.

다만 가상화를 도입하면 행 높이를 미리 알거나 측정해야 하고, 화면 밖으로 나간 항목의 키보드 초점·선택 상태 유지, 스크린리더 탐색, 브라우저의 페이지 내 검색(Ctrl+F)이나 인쇄가 까다로워지는 비용이 따릅니다. 만약 ‘페이지당 100개 보기’ 같은 페이지네이션으로 요구사항을 충분히 만족할 수 있다면 페이지네이션이 훨씬 단순하고 안전한 선택일 수 있습니다.

코드 예제

동작을 설명하는 읽기 전용 예제입니다.

example.js
// 가정: rowHeight > 0, 나머지는 음수가 아니며 overscan은 정수
const first = Math.floor(scrollTop / rowHeight);
const start = Math.min(items.length, Math.max(0, first - overscan));
const end = Math.min(
  items.length,
  Math.ceil((scrollTop + viewportHeight) / rowHeight) + overscan
);
const visibleItems = items.slice(start, end);
javascript · 읽기 전용8줄

끝 인덱스 end는 slice에서 포함되지 않는 끝 경계입니다. 예를 들어 행 높이가 30px일 때 scrollTop=1, viewportHeight=30이면 0번 행과 1번 행이 화면에 걸쳐 보이므로 end는 2가 되어 두 행이 모두 포함됩니다(overscan=0 기준). 이 코드는 표시할 인덱스 범위만 계산하는 예제이며 실제 가상화에는 전체 스크롤 높이 유지와 초점 처리도 함께 필요합니다.

자주 헷갈리는 포인트

  • 무한 스크롤은 스크롤할 때 데이터를 서버에서 추가로 받아 오는 방식이고, 가상화는 화면에 그리는 DOM 개수를 제한하는 방식이므로 둘은 같은 기능이 아닙니다.
  • 목록을 가상화해 DOM 개수를 줄이더라도, 매번 전체 배열을 비효율적으로 정렬·필터링하는 계산 비용 자체가 저절로 사라지지는 않습니다.

내 말로 설명해 보기

계산 시간은 짧은데 브라우저 Layout 시간이 길게 나오는 상황이라면, Worker·메모이제이션·페이지네이션·가상화를 어떤 기준으로 비교해 선택할까요?

생각할 단서 시간이 오래 걸리는 구간이 JavaScript 데이터 계산인지, 브라우저의 DOM 배치(Layout)인지 먼저 구분해 보세요.

예시 답변 확인

설명에 들어갈 핵심

  • Worker는 계산 스레드를 분리할 뿐 DOM Layout 비용을 대신 줄여 주지 않습니다
  • 페이지네이션과 가상화는 화면에 실제로 그리는 DOM 요소 수를 줄입니다
  • 고정 높이 범위 계산에서는 화면에 일부만 걸친 마지막 행도 포함해야 합니다

예시 답변

Layout 시간이 병목이라면 화면에 그리는 DOM 요소가 너무 많다는 뜻이므로 Worker로 정렬만 옮겨도 해결되지 않습니다. 우선 페이지네이션으로 한 번에 보여 줄 행 수를 줄일 수 있는지 검토하고, 연속 스크롤이 꼭 필요한 화면이라면 목록 가상화를 적용해 보이는 구간만 렌더링합니다.

문장을 그대로 외우기보다 예제의 값과 실행 흐름을 떠올리며 설명해 보세요.

실전 시나리오에 적용해 보기

함께 읽으면 좋은 개념

공식 참고 자료

← 프론트엔드 설계