#Frontend

DOM Reflow 100번을 1번으로 줄였더니 60fps가 돌아왔다

DOM Reflow 100번을 1번으로 줄였더니 60fps가 돌아왔다
01

Summary

브라우저 엔진을 길들이는 법: 100번의 Reflow를 단 1번으로 압축하다

React를 우회하고 4단계 배칭 시스템으로 레이아웃 스래싱을 정복하여 60fps를 탈환한 최적화 전략

이 아티클은 고성능 그래픽 에디터 개발 중 마주한 렌더링 성능 한계를 브라우저 내부 메커니즘 이해를 통해 해결한 과정을 담고 있습니다. 단순히 React 최적화에 그치지 않고, 브라우저 레이아웃 파이프라인을 직접 통제하는 '4-Phase 배칭 모델'을 설계하여 리플로우 비용을 극적으로 절감한 실전 노하우를 공유합니다.

  • 01React Reconciliation 모델이 고빈도 업데이트 요구사항에서 가질 수 있는 성능적 한계 분석
  • 02DOM의 읽기(Read)와 쓰기(Write)가 교차될 때 발생하는 레이아웃 스래싱 현상과 성능 저하 원인 규명
  • 03Task 기반의 4단계(PRE-READ-WRITE-POST) 배칭 매니저를 통한 브라우저 리플로우 최적화
  • 04직접 DOM 조작(Native Rendering)과 React 상태 관리 간의 효율적인 동기화 전략 수립
  • 05크롬 성능 프로파일러를 활용한 정량적인 성능 개선 지표(50ms → 0.5ms) 달성

RECOMMENDATION

에디터, 인터랙티브 대시보드, 타임라인 등 대량의 DOM 요소를 실시간으로 갱신해야 하는 프론트엔드 개발자에게 필수적인 읽을거리입니다. 프레임 드롭 문제로 고민 중이라면 브라우저 렌더링 파이프라인 관점에서의 접근법을 권장합니다.

The Problem

캔버스 에디터에서 여러 요소를 드래그할 때 수백 개의 DOM 노드가 동시에 업데이트되며 화면이 버벅이는 문제가 발생했습니다. 초기에는 React 렌더링 비용이 원인이라 판단했으나, 실제 병목은 DOM 읽기와 쓰기가 반복되며 발생하는 레이아웃 스래싱(Layout Thrashing)으로 인한 과도한 리플로우(Reflow)였습니다.

The Solution

React의 재조정 과정을 우회하여 DOM을 직접 조작하는 별도의 렌더링 파이프라인을 구축했습니다. 특히 DOM 작업의 순서를 제어하기 위해 모든 읽기(Read)를 먼저 수행하고 모든 쓰기(Write)를 나중에 수행하는 4단계 배칭(PRE, READ, WRITE, POST) 모델을 도입하여 레이아웃 계산을 1회로 제한했습니다.

The Result

100개 요소 드래그 시나리오 기준으로 프레임당 레이아웃 횟수가 약 100회에서 1회로 줄어들었으며, 레이아웃 소요 시간은 50ms에서 0.5ms로 대폭 단축되었습니다. 결과적으로 15~25fps에 머물던 프레임 레이트가 60fps로 복구되어 부드러운 사용자 경험을 제공하게 되었습니다.

Trade-off

React의 선언적 UI 모델 대신 직접 DOM을 제어하는 복잡한 상태 머신과 파이프라인을 유지보수해야 하는 부담이 생겼습니다. 또한 조작 중에는 React 상태와 실제 DOM이 일시적으로 괴리되므로, 조작 종료 시 idleCallback을 통해 수동으로 상태를 동기화하는 추가 로직이 필요합니다.

03

Key Concepts

Concept · 01

Layout Thrashing (레이아웃 스래싱)

DOM의 스타일을 변경(Write)한 직후, 최신 레이아웃 정보(Read)를 즉시 요청할 때 브라우저가 최신 값을 제공하기 위해 미뤄둔 레이아웃 계산을 강제로 수행하며 발생하는 성능 저하 현상입니다.

  • 쓰기와 읽기가 반복되면 한 프레임 내에서도 수많은 Reflow가 발생하여 CPU에 과부하를 줍니다.
  • 본문에서는 100개의 뷰가 각자 읽고 쓰는 패턴을 반복하여 프레임 타임을 초과하는 원인이 되었습니다.
Concept · 02

4-Phase Batching (4단계 배칭)

DOM 조작 작업을 PRE(준비), READ(읽기), WRITE(쓰기), POST(사후처리)의 4단계로 그룹화하여 실행 순서를 강제하는 렌더링 제어 방식입니다.

  • 모든 뷰의 READ 콜백을 모아 먼저 실행함으로써 브라우저가 레이아웃을 한 번만 계산하도록 유도합니다.
  • WRITE 단계 이후에는 동일 윈도우 내에서 READ를 금지하여 강제 리플로우 발생 가능성을 차단합니다.
Concept · 03

Native Rendering Pipeline

React의 가상 DOM 비교 및 리렌더링 과정을 거치지 않고, 브라우저 API를 사용하여 DOM 요소의 속성이나 스타일을 직접 갱신하는 고성능 전용 실행 경로입니다.

  • 드래그와 같은 고빈도 이벤트 발생 시 React를 우회하여 CSS Custom Property 등을 직접 수정합니다.
  • 성능이 중요한 구간에서는 직접 제어를 수행하고, 작업이 끝난 후 비동기적으로 React 상태와 재동기화합니다.