브라우저 랜더링
이전 DOM에 관해 글을 남긴 적이 있다.
면접을 보게 되면서 무언가 깔끔하고 장황하지 않게 정리한 점과 몰랐던 부분에 대해 기록으로 남겨보자 한다.
알고 있는데, 듣기 쉽고 알아듣기 쉽도록 말하는 것도 능력이지 않을까 싶다.
브라우저 랜더링 정리
- 브라우저는 HTML, CSS, JS, 이미지, 폰트 파일 등 랜더링에 필요한 리소스를 서버에 요청하고 응답을 받는다.
- 브라우저의 랜더링 엔진인 서버로 부터 응답받은 HTML, CSS를 파싱 하여 DOM과 CSSOM 트리를 생성하고 이 둘을 결합해 랜더 트리를 생성한다.
- 브라우저의 자바스크립트 엔진은 서버로 부터 응답받은 JS를 파싱 하여 AST(Abstract Syntax Tree)를 생성하고 바잍트 코드로 변환하여 이를 실행한다. 이때 js가 DOM API를 통해 DOM or CSSOM 트리를 변경한다면 변경된 DOM CSSOM은 다시 랜더 트리로 결합된다.
- 이렇게 랜더트리를 기반으로 HTML 요소의 레이아웃(위치, 크기)등을 계산하고 브라우저는 HTML 요소를 그린다.
여기서 랜더링 엔진은 각 브라우저 별로 다르다.
크롬 - 블링크 / 사파리 = 웹킷 / 파이어폭스 = 개코
그럼 여기서 면접 질문을 추가로 알아보자.
내가 받은 면접 질문은 브라우저가 js 즉, scirpt 태그를 만나면 어떻게 되는가? 였다
- 브라우저의 랜더링 엔진은 자바스크립트를 파싱 할 수 없기 때문에 자바스크립트 엔진으로 권한을 위임하게 되는데 이때 DOM 생성 프로세스를 중지하는 블로킹이 발생된다.
- 이후 자바스크립트 엔진의 파싱이 완료가 되면 중단되었던 시점으로 돌아가 다시 DOM을 생성한다.
여기까지는 나름 좋은 답변이라고 생각했는데, 그다음 질문에서 당황하였다.
그럼 CSS link, style 태그를 만났을때도 블로킹이 발생하나요?
나의 대답은 No 였다. 여기에서 딱 마무리되었다.- 이 질문을 마지막으로 2차 면접을 진행하였는데, 아무리 생각해도 잘 못 말한 것 같았다.
- 정답을 먼저 말하자면 Yes 이다.
내가 link, style이 블로킹이 발생하지 않았을 거라 생각했던 이유
- 브라우저의 랜더링 엔진이 html, css 파서를 모두 가지고 있으니 별도로 엔진에 위임을 할 필요가 없다고 생각했고 그렇기에 블로킹이 발생하지 않을 거라 생각했다.
2차 면접을 앞두고 생각해보니 아무리 생각해도 잘못 대답한 것 같았다.
- css를 통해서는 CSSOM 트리를 생성하는데, 그럼 DOM 생성 프로세스가 잠시 중단돼야 하지 않았을까?
- 그렇다, 답변을 제대로 하지 못했다. 이것이 내가 이 글을 포스팅하는 이유이다.
결국 브라우저의 랜더링 엔진은 HTML 문서를 한 줄 한줄 순차적으로 파싱 하다가 CSS를 로드하는 link style 태그를 만나면 DOM 생성 프로세스를 중지하고, CSSOM 생성하는 프로세스가 진행된다고 한다.
이렇게 생성된 DOM, CSSOM 트리를 통해 랜더 트리를 만들고 화면에 그리게 된다.
결론, link, style 태그를 만나면 DOM 생성 프로세스가 중단된다.
즉, CSS, JS는 브라우저 랜더링의 블로킹 요소로 작용한다.
추가사항
defet는 아는데 async는 무엇일까??
이에 대한 질문을 받지는 않았지만, css 블로킹을 보며 알게 된 내용을 기록으로 남긴다.
역시 무언가가 왜 생겨났는지 역사를 살펴보면 다 이유가 있다.
먼저, async / defer 속성은 왜 나오게 된 걸까?
이러한 자바스크립트에 의한 블로킹 현상을 해결하기 위해 HTML5부터 async defer 속성이 추가되었다.
async와 defer의 공통점
해당 속성 모두 HTML 파싱과 자바스크립트 파일 로드를 비동기적으로 동시에 진행하게 만들어 준다고 한다.
async 와 defer 의 차이점
자바스크립트 실행 시점의 차이가 존재한다.
async
자바스크립트 파싱과 실행이 파일이 로드된 직후 바로 진행이 되기 때문에 이때 HTML 파싱이 중단된다.
즉, 비동기적으로 동시에 진행이 가능하지만, 완료된 순서로 실행되기 때문에 실행 순서를 보장할 수 없다.
즉 async를 사용해도 DOM 생성 프로세스가 중단될 가능성이 있다.
defer
자바스크립트 파일을 비동기적으로 동시에 로드를 한다.
여기서 async와 다르게 HTML 파싱이 완료된 직후, 즉 DOM을 생성한 이후에 자바스크립트를 파싱 하고 실행한다.
DOM 생성 프로세스 진행 중 자바스크립트에서 DOM API를 통해 DOM을 조작하면 예기치 못한 에러를 발생시킬 수 있는데 결국 이러한 문제를 방지하는 역할을 한다.
왜 async는 보지를 못했는데, defet는 알고 있는지 이유도 해결해 보았다.
랜더링 참고자료
2: https://coffeeandcakeandnewjeong.tistory.com/34