** 이전 포스팅에서 렌더트리를 형성하는 과정에(웹브라우저 동작 과정) 대해서 포스팅했는데, 추가적으로 이번엔 렌더링 엔진은 아니지만 자바스크립트 엔진에 의해서 이뤄지는 자바스크립트 코드 파싱 과정에 대해서, 그리고 리렌더링 과정에 대해서 포스팅을 하고자 한다.
자바스크립트(JS) 파싱 및 실행 과정
- CSS와 마찬가지로, HTML 파싱 과정에서 script 태그 속 js 코드나, link 태그로 불러온 js 파일을 만나게 될 때, 렌더링 엔진은 파싱 및 DOM 생성을 멈추고, 해당 코드를 파싱 및 실행하게 된다(script 태그를 body 태그 마지막에 쓰는 것이 좋은 이유로, js 로직이 복잡하다면, 렌더링에 그만큼 로딩시간이 걸리기 때문에 순차적으로 코드를 파싱하는 렌더링 과정에서 body 태그 다음에 script 태그를 삽입하는게 추천된다)
- 이 때, 렌더링 엔진이 진행하던 작업의 주도권을 자바스크립트 엔진에게 넘겨준다. 즉, 자바스크립트 파싱 및 실행은 자바스크립트 엔진이 담당하게 된다(브라우저별로 렌더링 엔진도 다르듯이, 자바스크립트 엔진도 다르다. 예를 들어, 구글 크롬 및 node.js가 쓰는 V8도 있고, 파이어폭스가 쓰는 SpiderMonkey도 있다).
- 먼저, 자바스크립트 코드(개발자가 타이핑했을)를 받은 자바스크립트 엔진은 그것을 읽을 수 없기에 역시 파싱 과정이 필요하다. 따라서, 코드를 먼저 최소의 문법 단위인 토큰 으로 '토크나이징(tokenizing)' 한다. 이는 DOM 트리 생성 과정에서도 나왔던 개념으로 어휘 분석 과정으로도 불린다(Lexcial Analysis).
- 다음으로, 어휘 단위로 혹은 최소의 문법적 단위로 코드를 쪼갰으니, 이제 그 쪼갠 단위를 바탕으로 구문분석(syntax analysis)을 진행한다. 이 과정을 바탕으로 AST(Abstract Syntax Tree)를 생성한다(파싱 과정).
** AST explorer 실제로 해당 사이트에 들어가면, 자바스크립트 코드를 AST 형태로 컨버팅한 것을 볼 수 있게 해뒀다.
- 이렇게 파싱한 AST를 바이트코드로 변환해서 이를 실행할 수 있는 인터프리터를 통해 실행을 하게 된다.
리플로우와 리페인트 과정
- 저번 포스팅 마지막 부분에 나온 '리렌더링'에 관련한 내용인데, 이미 렌더링 엔진을 통해 최종적으로 렌더트리를 생성해서, 레이아웃, 페인트 과정을 거쳐 브라우저의 뷰포트에 렌더링을 마친 상태에서 유저의 특정 동작으로 인해 인터랙션이 발생하고(by JS), DOM API를 통해 DOM 혹은 CSSOM(CSS + DOM)에 영향을 미쳤다고 가정해보자.
** DOM API란 이미 생성된 DOM을 동적으로 조작할 수 있도록 (html 요소와 스타일 등을 변경할 수 있는) 만들어 놓은 프로그래밍 인터페이스이다.
** 주의점 : 앞서 말했듯이 html 렌더링 과정은 동기적(synchronous)으로 처리되기 때문에 중간에 js 리소스를 불러오면 js 코드가 최종 실행될 때까지 파싱과 DOM 생성을 멈춘다(blocking). 하지만, 이 때, JS 코드가 DOM API를 이용하여 DOM 혹은 CSSOM을 수정하는 로직이라면, 문제가 발생한다. DOM API는 이미 완성된 렌더트리에 DOM에 대해서 사용할 수 있는데, 아직 생성중인 단계에서 DOM API를 사용하면 문제가 생기는 것이다. 애초에 아직 그려지지 않은 부분에 대해서 수정을 하려하면 에러가 나는 것이 상식적인 것이기도 하다;
- 그러면,다시 변경된 DOM, CSSOM을 바탕으로 렌더트리가 생성되고, 또 이를 바탕으로 레이아웃, 페인트 과정이 이뤄지는데, 레이아웃을 새로짜는 것을 리플로우, 페인트를 다시하는 것을 리페인트라고 한다.
- 리플로우는 노드의 추가, 제거 및 요소의 크기, 위치 변경 등 레이아웃과 관련된 부분이 수정되는 경우에 발생하고, 리페인트는 재결합된 렌더트리를 기반으로 다시 페인트를 하는 경우를 말하기 때문에 각각의 과정은 반드시 리플로우가 일어나고, 리페인트가 일어나는 식이 아니라 리플로우가 안일어나고(레이아웃에 변화x인 경우), 리페인트만 일어날 수 있다.
자바스크립트 파싱에 의한 DOM 생성 Blocking