대용량 문서용 에디터 성능 최적화 방법
요약
수천 개의 노드가 포함된 문서를 contenteditable 영역에서 직접 처리하면 심각한 지연 현상이 발생할 수 있습니다. 이 팁은 대규모 콘텐츠를 위한 메모리 및 렌더링 최적화 기법을 다룹니다.
문제 상황
대형 contenteditable 영역에서 키를 누를 때마다 브라우저에서는 “스타일 재계산(Recalculate Style)” 및 “레이아웃(Layout)” 이벤트가 발생합니다. DOM의 깊이가 너무 깊거나 크기가 너무 크면 이벤트 루프가 차단되어, 사용자가 타이핑한 후 수백 밀리초 뒤에 글자가 나타나는 “타이핑 버벅임” 현상이 발생합니다.
모범 사례
1. 전역 리렌더링 피하기
변경이 있을 때마다 문서 전체를 다시 렌더링하지 마세요. 변이된 특정 DOM 노드만 업데이트하는 **부분 렌더링(Partial Rendering)**을 지원하는 프레임워크(Lexical, ProseMirror 등)를 사용해야 합니다.
2. UI 가상화 (무한 스크롤)
100페이지가 넘는 초대형 문서의 경우 **가상 선택(Virtual Selection)**을 구현하세요. 현재 뷰포트에 보이는 섹션만 렌더링하는 방식입니다.
- 과제: 가상화된 에디터에서 선택 및 검색은 매우 복잡하며, 대개 브라우저의 기본 검색/선택 엔진을 위해 보이지 않는 가짜 DOM을 유지하는 “포털” 시스템이 필요합니다.
3. 모델 동기화 스로틀링 (Throttling)
에디터 상태를 데이터베이스나 협업 서버와 동기화할 때, “모델-JSON” 직렬화 과정을 스로틀링하세요.
// 모든 'input' 이벤트마다 실행하지 마세요
const debouncedSync = debounce((editorState) => {
saveToDatabase(editorState.toJSON());
}, 1000);
4. 노드 복잡도 최적화
DOM 구조를 최대한 평평하게 유지하세요. <div><div><p>...</p></div></div> 대신 가능한 한 평평한 p 노드 리스트를 사용하세요. 구조가 깊게 중첩될수록 브라우저의 BiDi 또는 레이아웃 계산 시간이 기하급수적으로 늘어납니다.
주의 사항
- 페이지 내 검색: 가상화된 에디터는 브라우저 기본
Cmd + F검색을 무력화합니다. 커스텀 검색 UI를 직접 구현해야 합니다. - 블록을 가로지르는 선택: 가상화가 적용되면 사용자가 렌더링되지 않은 부분까지 드래그하여 텍스트를 선택하는 것이 불가능해질 수 있습니다.