HTML이 렌더링 중에 JavaScript가 실행되면 멈추는데 그 이유는 무엇일까요?
면접용
HTML이 렌더링되는 도중에 JavaScript가 실행되면 브라우저는 렌더링을 멈추고 JavaScript 코드를 먼저 실행합니다. 그 이유는 브라우저가 HTML을 해석하고 화면을 그리는 과정(렌더링)과 JavaScript 실행이 동일한 메인 스레드에서 처리되기 때문입니다.
자바스크립트는 기본적으로 싱글 스레드 환경에서 동작하기 때문에, 실행 중인 코드가 끝나야 다음 작업을 진행할 수 있습니다. 그래서 HTML을 파싱하는 도중 태그를 만나면, 브라우저는 먼저 해당 JavaScript를 실행하고, 실행이 끝난 후에야 다시 HTML 파싱을 이어갑니다.
이 때문에 스크립트 실행이 오래 걸리면 화면 렌더링이 지연될 수 있습니다. 이를 방지하기 위해 defer 또는 async 속성을 사용하면 브라우저가 HTML을 계속 파싱하면서 JavaScript를 비동기적으로 실행할 수 있습니다.
개념 설명
JavaScript 실행과 HTML 파싱의 관계
브라우저는 기본적으로 **싱글 스레드(Single Thread)**에서 동작합니다. 즉, 한 번에 하나의 작업만 실행할 수 있습니다. 이 때문에 HTML을 파싱하는 작업과 JavaScript를 실행하는 작업이 같은 메인 스레드에서 처리됩니다.
브라우저가 HTML을 읽는 도중 <script> 태그를 만나면, HTML 파싱을 멈추고 해당 JavaScript를 먼저 다운받고 실행합니다. JavaScript 실행이 완료된 후에야 다시 HTML을 해석하고 화면을 렌더링할 수 있습니다. 이 과정에서 JavaScript 실행 시간이 길어지면 렌더링이 지연될 수 있으며, 사용자가 빈 화면을 보게 되는 경우도 발생할 수 있습니다.
이런 브라우저의 동작 방식은 두 가지 중요한 이슈를 만듭니다.
스크립트에서는 스크립트 아래에 있는 DOM 요소에 접근할 수 없습니다. 따라서 DOM 요소에 핸들러를 추가하는 것과 같은 여러 행위가 불가능해집니다.
<!DOCTYPE html> <html lang="ko"> <head> <title>DOM 접근 문제</title> <script> document.getElementById("myButton").addEventListener("click", function() { alert("버튼 클릭됨!"); }); </script> </head> <body> <!<script>가 실행될 때 아직 <button> 요소가 생성되지 않았기 때문에 오류 발생> <button id="myButton">클릭하세요</button> </body> </html>페이지 위쪽에 용량이 큰 스크립트가 있는 경우 스크립트가 페이지를 ‘막아버립니다’. 페이지에 접속하는 사용자들은 스크립트를 다운받고 실행할 때까지 스크립트 아래쪽 페이지를 볼 수 없게 됩니다.
해결 방법
이러한 문제를 방지하기 위해 <script> 태그에 async 또는 defer 속성을 추가하면 JavaScript가 HTML 파싱을 막지 않도록 조정할 수 있습니다. Javascript 다운은 네트워크 스레드가 실행하기 때문에 병렬로 다운받을 수 있습니다. 기존에는 script.js를 만나면 다운받고 실행해서 다운받을 js 용량이 크거나 하면 성능 저하가 있을 수 있었는데, async, defer는 script.js를 병렬로 다운받아 문제를 해결합니다.
asyncJavaScript 파일을 HTML과 병렬로 다운로드한 후, 다운로드가 완료되는 즉시 실행합니다. 하지만 실행 순서는 보장되지 않으므로, 스크립트 간의 의존성이 있을 경우에는 주의해야 합니다.
deferJavaScript 파일을 HTML과 병렬로 다운로드하면서도, HTML 파싱이 완전히 끝난 후 실행됩니다. 따라서 DOM을 조작하는 코드가 있을 때 적합하며, 여러 개의
defer스크립트는 작성된 순서대로 실행됩니다.DOMContentLoaded이벤트defer속성과 유사한 방식으로, HTML이 완전히 파싱된 후 JavaScript를 실행하고 싶다면DOMContentLoaded이벤트를 사용할 수도 있습니다.HTML이 모두 로드되고,
defer스크립트까지 실행된 후DOMContentLoaded이벤트가 발생합니다.
Last updated