(이 시리즈를 쓰게 된 계기는 사실 이걸 말하고 싶어서 열심히 빌드업 한것이다.)
(근데 생각보다 글쓰니까 공부가 더 잘되는 느낌이네)
여기까지 공부 한 후 공부한 내용을 자랑확인 하고 싶어 동료에게 물어봤다.
나: "##님 저 오늘 랜더링 공부함 ㅎㅎ"
##: "오 그거 중요해요 리플로우, 리페인트, defer, async까지 공부하면 돼요"
나: "아직 최적화 까지는 공부 못했고 defer, async는 알아요!"
##: "body 끝에 script가 있으면 FP가 빨라지는것도 아시나요?"
(Placing scripts at the bottom of the <body> element improves the display speed, because script interpretation slows down the display.)
나: "어? 그럼 script 태그때문에 DOM 파싱이 중지 되는데 HTML이 전부 파싱되지 않아서 Paint가 실행이 안되는거 아닌가요?"
###: "???"
나: "???"
그래서 테스트를 해봤다.
perfomance를 체크 하기위해서는 외부에서 접근 가능한 환경을 만들어야 했고
환경 구축하는데 시간이 걸릴것 같아 그냥
Google Developers: 주요 렌더링 경로 성능 분석에 있는 예제 둘을 사용 했다.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
<script src="app.js"></script>
</body>
</html>
측정 결과 예상대로 Load가 먼저 발생하고 DOM Contents Loaded가 완료됐다. 즉 스크립트가 실행되는동안 DCL이 완료되지 못한다.
Performance탭을 봐도 Load가 먼저 발생하고 DCL이 발생하고 FP가 발생한다.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<title>Critical Path: Script Async</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
<script src="app.js" async></script>
</body>
</html>
확실히 DCL을 script가 block하지 않는다.
DCL이 완료된 후 FP가 진행되고 Load가 진행된다.
네이버는 어떤지 보는 순간 동공에 지진이 발생했습니다.
FP가 DCL보다 먼저 일어난 것 입니다....ㄷㄷ
분명 DOM/CSSOM 완료되면 Render Tree가 만들어진다 했는데..
그래서 Google 검색을 했고 stackoverflow에서 저와 같은 의문을 질문 한 글을 발견합니당.
해당 글 : why first paint is happening before domcontentloaded?
해답은 Browser가 Render Tree를 점진적으로 만든다는 것과 부분적으로 병렬작업으로 진행한다는 것이었습니다.
즉, DOM 생성하다가 Script태그를 만나서 HTML파싱을 멈추게 되더라도
script execute전에 CSSOM이 완성되고
script execute와
부분적으로 파싱된 DOM과 완성된 CSSOM을 가지고
Render Tree를 생성해 부분적인 Rendering을 하는 것은 병렬적으로 진행 된다면
Body 끝에 script를 두어 FP를 빠르게 할 수 있다.(DCL이 늦은것도 맞음)
그리고 DOM트리는 점진적 생성
CSSOM 트리는 한번에 다만들어야 함 (but, 빠름).CSS의 C는 'Cascade(종속)'이고 CSS 규칙은 계단식으로 내려간다.
후속 규칙이 이전 규칙을 재정의 할 수있기 때문에
CSSOM트리가 점진적으로 만들어지면
매번 DOM과 결합하여 RenderTree를 만들고
Layout과 Paint를 진행 할텐데
CSSOM트리가 변하게 되면
이 모든 Render 과정을 다시 해야하는 상황이 발생하므로 매우매우 비효율적
참고 : MDN Web Performance
(현재 공부한 지식들을 갖고 도식화 해본 것이라..정확하지 않을 수 있습니다.(Layout과 Paint가 다시 일어나는 경우 생각하지않음) 혹시 의문이 있으면 댓글로 남겨주시면 생각해보고 답변 달겠습니당!)
MDN의 DOMContentLoaded설명과
Google의 DOMContentLoaded가 다르다!!
MDN에서는 DOM이 완성된 시기라고 하고
Google에서는 DOM과 CSSOM이 준비되어 Render tree를 그릴 수 있는 상태라고...
그런데 google에서도 잘 읽어보면 dom이 완성되고 스크립트실행을 막는 css가 없는 상태라고 한다.
그럼 또 둘 다 맞는 말이다.
앞선 예제들에서 DCL이 HTML파싱 직후 일어난 그래프들을 확인하면 CSS로드와 JS로드도 일어나기 전 DOM이 완성됐다.
아마도 브라우저는 내장되어있는 스타일로 CSSOM을 만들어서 Render Tree를 생성하여 Render를 미리 진행 하지 않았나 추측해본다.