인프런 커뮤니티 질문&답변
렌더링 차단 리소스 javascript 실행에 관련해서 질문 있습니다.
해결된 질문
작성
·
39
0
안녕하세요? 수업을 듣다 질문이 있어서 남기게 됐습니다!
브라우저가 렌더링 과정이 DOM & CSSOM -> Render Tree -> layout 단계 -> Paint -> Compositing 단계 순서로 이해하고 있습니다.
이번 수업에서는 <script src="url"></script>를 발견하면 DOM 파싱을 멈추고 script 파일을 다운 후에 script가 먼저 실행한 다음 DOM을 다시 파싱 하는 걸로 이해했습니다.
여기서 궁금한게 생겼는데요. <body> 끝에 script 태그가 있고, script 코드 내용에서 DOM에 접근해서 한 요소의 widht, height, background를 변경하는 코드가 있어 먼저 실행 되었다면 브라우저 렌더링 어느 부분에 영향을 미치는지 궁금합니다.
제가 생각하기에는 script가 먼저 실행되고 나머지 파싱이 되는거라는 수업 내용에 따르면 DOM & CSSOM에서 적용이 된 후 다음 단계들을 따를 것 같습니다.
이 수업을 듣기 전에는 리플로우, 리페인트 과정이 있을 거라고 생각했으나 리플로우, 리페인트 과정이 없겠다는 생각이 들어 질문하게 되었습니다.
감사합니다.
퀴즈
DOMContentLoaded 이벤트는 언제 발생할까요?
모든 리소스 로드 후
DOM 구조 구축 완료 시
페이지가 닫히기 직전
스크립트 실행 직전
답변 2
1
안녕하세요 eddie님! 질문 주셔서 감사합니다. 질문해주신 바디 태그 최하단에 스크립트가 위치하고 그 내부에서 DOM의 너비, 높이, 배경색을 변경할 때 어떤 일이 발생하는지에 대해 상세한 예시 코드와 함께 확실하게 짚어드리겠습니다.
우선 결론부터 말씀드리자면, eddie님이 이 수업을 들으시기 전에 생각하셨던 것처럼 리플로우와 리페인트 과정이 발생하는 것이 맞습니다. 브라우저의 파서는 HTML 문서를 위에서 아래로 순차적으로 읽어 내려가며 DOM 트리를 구축합니다.
파서가 바디 태그 가장 끝에 도달하여 스크립트 태그를 만나면, eddie님이 이해하신 대로 남은 HTML 문서의 파싱을 잠시 멈추고 자바스크립트를 다운로드 및 실행하게 됩니다. 하지만 여기서 중요한 포인트는 스크립트가 실행되는 그 시점에는 이미 스크립트 태그 위에 작성된 HTML 요소들이 파싱되어 DOM 트리에 추가되어 있다는 사실입니다.
브라우저는 초기 DOM과 CSSOM을 결합해 렌더 트리를 만들고 화면에 그릴 준비를 하는데, 자바스크립트가 개입하여 이미 만들어진 DOM 노드의 스타일을 동적으로 변경하게 되면 브라우저는 렌더링 파이프라인의 특정 단계를 다시 실행해야만 합니다. 구체적인 동작 원리를 아래의 예시 코드를 보며 설명해 드리겠습니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>렌더링 테스트</title>
<style>
#box {
width: 100px;
height: 100px;
background-color: blue;
}
</style>
</head>
<body>
<div id="box">테스트 박스</div>
<script>
// 파서가 여기까지 도달하면 파싱을 멈추고 아래 코드를 실행합니다.
const boxElement = document.getElementById('box');
// DOM에 접근하여 요소의 기하학적 속성(width, height)을 변경합니다.
boxElement.style.width = '200px';
boxElement.style.height = '200px';
// 요소의 시각적 속성(background)을 변경합니다.
boxElement.style.backgroundColor = 'red';
</script>
</body>
</html>위 코드를 살펴보시면, 브라우저가 위에서부터 문서를 읽어 내려오며 아이디가 box인 div 요소를 먼저 DOM 트리에 등록합니다. 그리고 문서 끝에서 자바스크립트가 실행되면서 해당 요소의 속성을 동적으로 변경하게 됩니다. 이때 너비와 높이 값은 요소의 기하학적 크기와 위치를 결정하는 속성입니다.
자바스크립트가 이 값을 변경하는 순간, 브라우저는 이 요소뿐만 아니라 영향을 받는 주변 요소들의 위치와 크기를 다시 계산해야 하며, 이 과정이 바로 레이아웃 단계의 재실행, 즉 리플로우입니다. 크기와 위치 계산이 끝나면 화면에 새로운 색상인 빨간색을 입혀야 하는데, 배경색과 같이 요소의 기하학적 구조에는 영향을 주지 않고 시각적인 형태만 바꾸는 속성이 변경되었으므로 페인트 단계가 다시 실행되는 리페인트가 연이어 발생하게 됩니다.
즉, 스크립트가 HTML 파싱을 잠시 멈추는 것은 맞지만, 이미 생성된 DOM 객체를 자바스크립트로 조작하는 행위 자체는 렌더링 엔진에게 렌더 트리를 업데이트하고 화면을 다시 그리라는 명령을 내리는 것과 같기 때문에 리플로우와 리페인트를 피할 수 없는 것입니다.
이해를 위해 다시 한 번 렌더링 파이프라인의 핵심 용어 하나하나를 순서대로 짚어드리자면 다음과 같이 설명할 수 있습니다. 먼저 파싱은 브라우저가 HTML이나 CSS 코드를 읽고 이해할 수 있는 구조로 변환하는 과정을 말합니다. 이 과정을 통해 HTML 문서의 각 요소들을 트리 형태로 구성하여 자바스크립트가 접근하고 조작할 수 있도록 만든 문서 객체 모델이 바로 DOM이며, CSS 스타일 정보들을 모아 트리 형태로 구성한 것이 CSSOM입니다.
브라우저는 이 DOM과 CSSOM을 결합하여 화면에 실제로 그려질 요소들만 모아 렌더 트리라는 최종 트리를 구축하게 됩니다. 렌더 트리가 완성되면 이를 기반으로 각 요소가 화면의 어느 위치에 어느 정도의 크기로 배치될지 기하학적인 형태를 계산하게 되는데, 이를 레이아웃 또는 리플로우라고 부릅니다.
크기와 위치 계산이 끝난 후에는 실제 픽셀을 채워 넣어 색상이나 이미지 같은 시각적인 부분들을 화면에 그리게 되며, 이 단계를 페인트 또는 리페인트라고 합니다. 마지막으로 페인트 단계에서 그려진 여러 레이어들을 하나로 합성하여 최종적으로 화면에 표시하는 단계를 컴포지팅이라고 합니다.
이러한 렌더링 과정을 직접 눈으로 확인하고 실습해 보시려면, 크롬 브라우저의 개발자 도구를 열고 성능 탭을 적극적으로 활용해 보시는 것을 추천해 드립니다. 성능 탭에서 새로고침 버튼 모양인 기록 아이콘을 누르고 페이지가 로드되는 과정을 캡처해 보시면, 하단 이벤트 로그나 메인 스레드 작업 내역에서 스타일 재계산, 리플로우, 리페인트 이벤트가 자바스크립트 실행 직후에 연달아 발생하는 것을 명확하게 확인하실 수 있습니다. 자바스크립트 코드를 지웠을 때와 추가했을 때의 성능 기록을 비교하면서 추적해 보시면 자바스크립트 코드가 렌더링 파이프라인에 미치는 영향을 훨씬 더 깊고 확실하게 체득하실 수 있을 것입니다.
여기에 덧붙여, 현업 실무에서 렌더링 성능을 끌어올리기 위해 이러한 리플로우와 리페인트를 최소화하는 몇 가지 유용한 최적화 노하우를 가이드로 나누어 드리겠습니다.
첫 번째로 돔 조작은 한 번에 모아서 처리하는 것이 좋습니다. 자바스크립트로 요소의 스타일을 여러 번 나누어 변경하면 그 횟수만큼 리플로우가 발생할 수 있으므로, 가급적 변경할 스타일들을 CSS 클래스로 미리 정의해두고 클래스명 하나를 조작하여 스타일을 한 번에 일괄 변경하는 것이 성능에 훨씬 유리합니다.
두 번째로 애니메이션을 구현할 때는 트랜스폼과 오퍼시티 속성을 활용하는 것이 바람직합니다. 요소의 크기나 위치를 직접 조작하면 매 프레임마다 리플로우가 발생하여 화면이 뚝뚝 끊기는 현상이 발생할 수 있지만, 해당 속성들을 사용하면 리플로우와 리페인트를 건너뛰고 바로 합성 단계만 거치기 때문에 그래픽 카드의 도움을 받아 훨씬 부드러운 렌더링이 가능해집니다.
세 번째로 보이지 않는 상태에서 돔을 다루는 방법이 있습니다. 특정 컨테이너 안에 아주 많은 돔 조작이 필요하다면 먼저 해당 요소를 화면에서 숨겨 리플로우를 한 번만 발생시킨 후, 그 상태에서 필요한 모든 조작을 마치고 다시 화면에 보이게 하여 중간 과정에서의 불필요한 렌더링을 막을 수 있습니다. 또한 가상의 돔 공간인 도큐먼트 프래그먼트를 활용하여 메모리상에서 노드를 모두 완성한 후 실제 돔에 단 한 번만 추가하는 방법도 실무에서 매우 자주 쓰이는 패턴이니 꼭 참고해 보시기 바랍니다.
이렇게 좋은 질문 주셔서 감사합니다. eddie님처럼 원리를 파고드는 열정적인 수강생분들이 남겨주시는 예리한 질문들은 제가 앞으로 더 깊이 있는 강의를 제작하고 커리큘럼을 발전시키는 데 정말 큰 도움이 됩니다. 감사의 마음을 담아, 저희 우리 동네 코딩 스튜디오에서 제공하는 강의 중 추가로 필요하거나 수강하고 싶으신 강의가 있다면
jeony0535@naver.com으로 언제든지 편하게 연락해 주시기 바랍니다.
확인 후 원하시는 강의의 수강 쿠폰을 기쁜 마음으로 전달해 드리겠습니다. 앞으로도 학습하시면서 궁금한 점이 생기시면 언제든 편하게 질문 남겨주세요. eddie님의 프론트엔드 학습을 항상 진심으로 응원합니다!
감사합니다!
0
안녕하세요, 인프런 AI 인턴입니다. eddie님.
브라우저의 렌더링 과정과 자바스크립트의 실행 순서를 이해하고 계신 점에서 이미 좋은 기반을 갖추고 계십니다. 질문해주신 내용에 대해 상세히 설명드리겠습니다.
브라우저의 렌더링 과정은 말씀하신 대로 DOM & CSSOM의 생성 -> Render Tree -> Layout -> Paint -> Compositing의 순서로 진행됩니다. <script> 태그가 발견되면 기본적으로 다음과 같은 흐름이 발생합니다:
DOM 파싱 멈춤:
<script src="url"></script>태그를 만나면, 브라우저는 DOM 파싱을 멈추고 스크립트를 다운로드 및 실행합니다.스크립트 실행 후 영향: 스크립트에서 DOM에 접근하여 요소의 속성(예: width, height, background 등)을 변경하는 경우, 브라우저는 해당 변경을 렌더 트리에 반영하기 위해 리플로우 혹은 리페인트 과정을 필요로 합니다.
리플로우(Reflow): DOM 구조나 요소의 크기 및 위치가 변경되는 경우, 브라우저는 레이아웃을 다시 계산하여 요소들의 위치를 재조정합니다. 이 과정은 전체 페이지 레이아웃에 영향을 미칩니다.
리페인트(Repaint): 요소의 색상, 배경색 등의 시각적 특성만 변경된 경우, 레이아웃 재계산이 필요 없고 색상만 다시 그리게 됩니다.
적절한 시점의 예외 처리: 스크립트가
<body>태그 끝에 위치해 있다고 가정하면, 이 스크립트는 다른 DOM 요소들이 이미 렌더링된 이후에 실행됩니다. 이 경우, 실행 시점에서 스크립트가 DOM에 접근하여 변경을 시도할 수 있고, 만약 해당 요소들이 이미 렌더된 상태라면, 렌더링에 있어서 추가적인 리플로우나 리페인트 과정을 유도할 수 있습니다.
일반적으로 성능을 최적화하기 위해, 비동기(<script async>) 또는 지연(<script defer>) 속성을 사용하여 스크립트가 DOM 파싱에 영향을 미치지 않도록 설정하는 것이 좋습니다. 그러면 렌더링 지표를 향상시킬 수 있습니다.
추가적으로 관련 강의와 질문을 참고하시면 도움이 되실 것입니다:
- 브라우저 렌더링 과정 및 성능 최적화 방법
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.





답변 주셔서 감사합니다!
처음에 브라우저 단계에만 매몰 되어 있다 보니 해당 단계에서 무엇이 계산 되는지 명확하게 이해하지 못한 상태여서 질문을 드렸던거 같습니다!
질문에 대한 내용에 대해서 자세히 알려주시고, 최적화 노하우까지 알려주셔서 다시한번 감사드립니다!