
대부분의 프로그래밍 언어는 운영체제(Operating System, OS)나 가상 머신(Virtual Machine, VM) 위에서 실행되지만 웹 애플리케이션의 클라이언트 사이드 자바스크립트는 브라우저에서 HTML, CSS와 함께 실행된다. 따라서 브라우저 환경을 고려할 때 더 효율적인 클라이언트 사이드 자바스크립트 프로그래밍이 가능하다.
이를 위해 브라우저가 HTML, CSS, JavaScript로 작성된 텍스트 문서를 어떻게 파싱(해석)하여 브라우저에 렌더링 하는지 알아보자.
파싱(parsing, syntax analysis)
프로그래밍 언어의 문법에 맞게 작성된 텍스트 문서를 읽어 들여 실행하기 위해 텍스트 문서의 문자열을 토큰으로 분해하고, 토큰의 문법적 의미와 구조를 반영하여 트리 구조의 자료구조인 파스 트리를 생성하는 일련의 과정
렌더링(rendering)
HTML, CSS, JavaScript로 작성된 문서를 파싱하여 브라우저에 시각적으로 출력하는 것
브라우저는 다음과 같은 과정을 거쳐 렌더링을 수행한다.

브라우저는 렌더링에 필요한 리소스(HTML, CSS, JavaScript, 이미지, 폰트, 파일 등)를 요청하고 서버로부터 응답을 받는다.

브라우저의 렌더링 엔진은 서버로부터 응답된 HTML, CSS를 파싱하여 DOM과 CSSOM을 생성하고 이들을 결합하여 렌더 트리를 생성한다.
렌더트리는 렌더링을 하기 위한 자료 구조로 브라우저 화면에 렌더링되지 않는 노드(meta 태그, script 태그 등)와 CSS에 의해 비표시 (display: none 등) 되는 노드들을 포함하지 않으며 렌더링이 되는 노드들로만 구성이 된다.



렌더 트리를 기반으로 HTML 요소의 레이아웃을 계산, 각 요소를 어디에 배치할지 결정
뷰포트 내에서 각 요소의 정확한 위치와 크기를 정확하게 캡처하는 Box 모델이 출력된다. (모든 상대적인 측정값은 화면에서 절대적인 픽셀로 변환됨)

브라우저 화면에 HTML 요소를 페인팅한다.
렌더링 트리의 노드를 화면의 실제 픽셀로 변환하게 된다. 레이아웃 단계에서 모든 계산이 완료되면, 화면에 모든 요소를 그리게 된다. 이 단계를 "페인팅"또는 "레스터화"라고 한다.
이미 레이아웃 단계에서 각 노드들의 위치, 크기, 색상 등 스타일이 모두 계산이 되었기 때문에 화면에 실제 픽셀로 변환하는 것
DOM은 HTML 문서를 구성하는 것 말고도 HTML 요소와 스타일을 변경할 수 있도록 DOM API를 제공하며 이를 통해 DOM을 제어하여 동적으로 조작할 수 있다.
HTML 문서를 순차적으로 한 줄씩 파싱하는 과정에서 CSS로드를 해서 link 태그나 style 태그를 만나면 DOM 생성을 위한 HTML 파싱을 일시적으로 중단하고 CSS 파싱을 통한 CSSOM을 생성하는 것과 마찬가지로 script 태그를 만나면 DOM 생성을 일시적으로 중단한다.
자바스크립트 코드를 만나게 되면 파싱을 시작하게 되는데, 이때 자바스크립트의 파싱은 브라우저의 렌더링 엔진이 아닌 자바스크립트 엔진이 처리한다.
자바스크립트의 파싱과 실행은 자바스크립트 엔진이 제어권을 넘겨받아 처리하는데 파싱 과정에서 CPU가 이해할 수 있도록 저수준 언어(Low-level language)로 변환하고 실행한다.
브라우저의 자바스크립트 엔진은 서버로부터 응답된 JavaScript를 파싱하여 AST(Abstract Syntax Tree)를 생성하고 바이트코드로 변환하여 실행하며, 이때 자바스크립트는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있다.

그리고 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합된다.
사용자가 웹사이트에 처음 접속을 하면, 위와 같은 렌더링 과정을 거쳐서 화면에 모든 요소가 그려지게 된다. 이후에 사용자는 다양한 액션을 수행하게 되고, 여기서 발생되는 이벤트로 인해서 HTML 요소가 추가되거나, 기존 요소의 스타일이 바뀌거나 하는 변경이 일어나게 된다.
이때 리플로우와 리페인트의 개념이 등장한다.
DOM의 레이아웃을 다시 계산하는 과정
요소들의 크기나 위치가 변경되면 브라우저는 문서의 전체 또는 일부 레이아웃을 재계산하여 화면에 다시 그려야한다.
리플로우는 상대적으로 비용이 높은 작업인데, 그 이유는 레이아웃을 재계산하기 때문에 문서의 크기가 크거나 변경 범위가 클 수록 성능에 영향을 줄 수 있기 때문이다.
재결합된 렌더트리를 기반으로 요소를 화면에 그리는 과정
리플로우와 달리 레이아웃은 변경하지 않으며, 단순히 화면에 보이는 내용을 다시 칠하는 작업이다.
리페인트는 리플로우보다 비교적 비용이 적은 작업이다.
하지만 요소가 많거나 빈번히 발생하면 성능 문제가 생길 수 있다.
즉, reflow와 repaint는 요소가 시각적으로 변경되었을 때, 변화를 계산하여 화면에 그려주는 작업을 말한다. DOM이 시각적으로 변경되면 reflow가 발생하여 변경된 렌더트리와 재결합 하고 재결합된 렌더트리를 기반으로 요소를 화면에 그리는 repaint가 발생한다.