성능이라는 거대한 벽

302025년 09월 14일4

데이빗의 반박은 조던 워크가 넘어야 할 가장 높은 벽이었다. 그는 팀 전체가 납득할 만한 해답을 내놓아야 했다. 단순히 “가짜 DOM을 쓸 겁니다”라는 선언만으로는 부족했다. 왜 그것이 해결책이 될 수 있는지, 그 원리를 증명해야만 했다.

조던은 화이트보드 앞에 서서, 브라우저가 화면을 그리는 과정을 설명하기 시작했다.

“우리가 jQuery로 $('#my-element').text('new text') 같은 코드를 실행하면, 브라우저 내부에서는 아주 복잡하고 비용이 많이 드는 작업들이 연쇄적으로 일어납니다.”

그는 과정을 하나씩 나열했다.

  1. DOM 파싱 및 수정: 브라우저는 거대한 DOM 트리에서 my-element를 찾고, 그 내용을 변경한다.
  2. 스타일 계산 (Recalculate Style): 요소 하나의 텍스트가 바뀌었을 뿐이지만, 브라우저는 페이지의 모든 요소에 어떤 CSS 규칙이 적용되는지 처음부터 다시 계산한다. 글자 크기, 색상, 여백 등이 모두 영향을 받을 수 있기 때문이다.
  3. 레이아웃 (Layout/Reflow): 변경된 요소의 크기나 위치가 바뀌었는지 확인하고, 그에 따라 다른 요소들의 위치도 연쇄적으로 다시 계산한다. 페이지 전체의 배치를 다시 짜는 과정이다.
  4. 페인팅 (Paint): 계산된 레이아웃에 따라, 화면의 각 부분을 실제로 픽셀 단위로 다시 그린다.
  5. 합성 (Composite): 그려진 여러 개의 레이어를 순서에 맞게 하나로 합쳐 최종 화면을 완성한다.

“문제는 이 과정이 믿을 수 없을 만큼 느리다는 겁니다. 특히 3번 레이아웃과 4번 페인팅 과정이 가장 큰 병목이죠. DOM을 한 번 건드릴 때마다 이 비싼 작업들이 동기적으로 실행됩니다. 만약 우리가 100개의 요소를 각기 다른 시간에 변경한다면, 이 끔찍한 과정이 100번 반복될 수도 있다는 뜻입니다.”

데이빗이 고개를 끄덕였다. “맞습니다. 그래서 우리는 성능 최적화를 할 때 DOM 접근 횟수를 최소화하려고 그토록 애쓰는 거죠.”

“바로 그겁니다.” 조던이 데이빗의 말을 받았다. “우리의 접근 방식은, 이 비싼 DOM 조작을 딱 한 번만, 정말 필요한 최소한의 변경에 대해서만 실행하자는 겁니다.”

그는 다시 한번 UI = render(data) 공식을 가리켰다.
“우리가 매번 전부 다시 그린다고 말한 것은, 이 느려터진 실제 DOM을 다시 그린다는 뜻이 아니었습니다. 자바스크립트 메모리 안에서, 순수한 객체로 이루어진 UI 설명서 트리를 다시 만든다는 의미였죠.”

그는 자바스크립트 객체를 조작하는 것과 실제 DOM을 조작하는 것의 속도 차이를 강조했다.
“자바스크립트 객체를 1000개 만들고 속성을 바꾸는 것은 눈 깜짝할 사이에 끝납니다. 하지만 실제 DOM 요소를 1000개 만들고 수정하는 것은 브라우저를 마비시킬 수도 있죠. 이 둘의 속도 차이는 수백, 수천 배에 달합니다.”

이제 팀원들은 조던이 그리려는 큰 그림을 어렴풋이 이해하기 시작했다.
모든 계산과 비교는 빠르고 가벼운 자바스크립트 메모리 안에서 일어난다. 그리고 그 계산이 모두 끝난 뒤, 최종적으로 변경이 필요한 부분만 정확히 골라내어, 느리고 무거운 실제 DOM에는 최소한의 ‘수술’만 가하는 것.

그것은 마치 건축가가 실제 건물을 부수고 다시 짓는 대신, 머릿속에서 수십 번 건물을 다시 설계해 보고, 최종 설계안이 나오면 인부들에게 “저기 3층 창문만 이걸로 교체해 주시오”라고 딱 한 번만 지시하는 것과 같았다.

하지만 여전히 의문은 남았다.
어떻게?
이전 설계도와 새 설계도를 비교해서 ‘3층 창문’만 바뀌었다는 것을 어떻게 그렇게 빠르고 정확하게 알아낼 것인가?

모든 시선이 다시 조던에게 향했다. 그들은 이제 성능이라는 거대한 벽을 넘을 수 있을지도 모른다는 희미한 희망을 품기 시작했다. 그리고 그 희망의 중심에는, 조던이 ‘가짜 DOM’이라고 부른 미지의 기술이 있었다.