Browser DOM and Script Loading

"브라우저는 HTML을 어떻게 DOM으로 만들고, JavaScript는 언제 어떤 방식으로 DOM에 접근해야 안전한가?" 이 page는 그 질문에 답한다. DOM은 정적인 HTML 텍스트를 브라우저가 이해하도록 메모리에 올린 객체 기반 트리 구조이고, JavaScript는 이 DOM 인터페이스로 화면 내용을 바꾼다.[1] Vue.js가 줄이려는 "직접 DOM 조작"의 대상이 이 트리이고, SPA and CSR에서 browser가 JavaScript로 UI를 rendering할 때 바꾸는 대상도 이 트리라고 볼 수 있다. 언어 규칙 자체는 JavaScript Language Model이 맡고, 이 page는 그 언어가 브라우저 문서와 만나는 지점을 다룬다.

DOM은 언어 밖의 API다

HTML에서 DOM 트리로

단계 과정명 설명
Step 1 Conversion 서버에서 받은 바이트(Bytes) 데이터를 지정된 인코딩에 따라 문자열로 변환
Step 2 Tokenization 문자열을 <html>, <body> 같은 의미 있는 단위인 토큰(Token)으로 분해
Step 3 Lexing 각 토큰을 속성과 규칙을 가진 노드(Node) 객체로 변환
Step 4 Construction 노드 간의 부모-자식 관계를 파악하여 최종적인 트리 구조(DOM) 완성

Script가 DOM 생성을 멈추는 방식

flowchart TD
  Parse["HTML을 읽으며 DOM 노드 생성"] --> Meet{"script를 만났는가"}
  Meet -- "아니오" --> Parse
  Meet -- "예" --> Block["DOM 생성 중단: JavaScript 다운로드와 실행"]
  Block --> Parse
<!DOCTYPE html>
<html>
<head>
	<title>JavaScript</title>
	<script>
		console.log("Hello JavaScript!! - title");
	</script>
</head>

<body>
	<h1>Hello</h1>
</body>

<script>
	console.log("Hello JavaScript!! - body");
</script>

</html>

Script 배치와 실행 시점

배치 실행 시점 스코프 DOM 접근 위험
<head>의 일반 script HTML을 읽다가 만나는 즉시 내려받아 실행하고, 그동안 DOM 생성이 멈춘다.[7:1] 전역 스코프를 공유한다.[11:2] 아래쪽 요소가 아직 노드가 아니어서 null 에러가 난다.[8:1]
<body> 아래(뒤)의 일반 script DOM 로딩이 끝난 뒤 쓰려고 <body> 아래에 둔다.[10:2] 전역 스코프를 공유한다.[11:3] 앞쪽 요소는 이미 노드로 만들어져 있어 위험이 줄어든다고 볼 수 있다.
type="module" script 기본적으로 defer처럼 HTML 파싱 후 실행된다.[11:4] 파일마다 독립 모듈 스코프를 갖고 strict mode로 실행된다.[11:5] 파싱 후 실행되므로, head 배치의 미생성 노드 문제를 피하는 또 다른 방법으로 읽을 수 있다.

이벤트 handler 연결

관련

테스트 질문

출처


  1. DOM.md (HTML) 12줄 — "DOM은 정적인 HTML 텍스트를 브라우저가 이해할 수 있도록 메모리에 적재한 객체 기반의 트리 구조입니다. 자바스크립트는 이 DOM이라는 인터페이스(API)를 통해 화면의 내용을 동적으로 변경합니다." ↩︎

  2. ECMAScript.md (Study) 42줄 — "브라우저의 DOM API, window, document, fetch 같은 기능은 JavaScript 실행 환경이 제공하는 API이며, ECMAScript 자체의 핵심 문법과는 구분된다." ↩︎

  3. DOM.md (HTML) 16-23줄 — "브라우저 엔진이 HTML을 읽어 DOM을 만드는 과정은 다음과 같습니다." 네 단계 표를 굵은 글씨 표기만 빼고 그대로 옮겼다. ↩︎

  4. DOM.md (HTML) 14, 16줄 — 절 제목 "DOM 생성 4단계 (Critical Rendering Path)"와 "브라우저 엔진이 HTML을 읽어 DOM을 만드는 과정은 다음과 같습니다." ↩︎

  5. 출처 공백 — CSSOM, render tree, layout, paint처럼 DOM 생성 이후의 rendering 단계는 이 batch의 어느 Raw에도 없다. ↩︎

  6. DOM.md (HTML) 31-37줄 — 공통점 "텍스트를 파싱하여 만든", AST "코드를 실행하기 위한", "실행 후에는 보통 사라짐", DOM "브라우저 화면을 유지하고 조작하기 위한", "자바스크립트로 언제든 수정 가능". ↩︎

  7. DOM.md (HTML) 44-46줄 — "브라우저는 HTML을 읽다가 <script>를 만나면", "자바스크립트 파일을 다운로드하고 실행할 때까지 DOM 생성이 멈춥니다." ↩︎ ↩︎

  8. DOM.md (HTML) 48줄 — "만약 <head>에서 DOM을 조작하려 하면, 아직 밑에 있는 HTML 요소들이 노드로 생성되지 않아 null 에러가 발생합니다." ↩︎ ↩︎

  9. DOM.md (HTML) 50줄 — "스크립트 실행이 길어지면 화면이 뜨지 않아 사용자가 답답해할 수 있습니다." ↩︎

  10. JavaScript.md 27-49줄 — "일반적으로 DOM 로딩이 완료된 후 사용하기 위해 <body>태그 아래에 위치", "페이지 내에서만 재사용 가능". HTML 예제 30-49줄을 그대로 옮겼다. DOM.md (HTML) 42줄의 절 제목도 "<script> 태그가 하단에 위치해야 하는 이유"다. ↩︎ ↩︎ ↩︎

  11. ECMAScript.md (Study) 980-994줄 — "브라우저에서 ESM을 사용하려면 script 태그에 type="module"을 지정한다.", "각 파일이 독립적인 모듈 스코프를 가진다.", "기본적으로 strict mode로 실행된다.", "import, export를 사용할 수 있다.", "top-level await를 사용할 수 있다.", "기본적으로 defer처럼 HTML 파싱 후 실행된다.", "일반 script는 전역 스코프를 공유하지만, module script는 파일마다 독립된 스코프를 가진다." ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  12. 출처 공백 — 이 batch의 Raw에는 module script가 "defer처럼" 실행된다는 비유(ECMAScript.md (Study) 992줄)만 있고, defer·async 속성을 직접 설명한 줄은 없다. ↩︎

  13. DOM.md (JavaScript) 37-38줄 — "inline 스타일: callback을 등록하지 않고 html 태그의 속성으로 handler를 직접 실행하는 형태", "html과 javascript가 섞임 - 관심사 분리가 되지 않아 유지보수가 어렵고 재사용성이 떨어짐". 바로 아래 39줄의 inline handler 안 this에 관한 문장은 확인할 근거가 없어 옮기지 않았다. ↩︎

  14. Event.md 15-16줄 — 절 제목 "이벤트 객체의 활용"과 "각 이벤트 별로 이벤트에 대한 상세 정보 포함" ↩︎

  15. 출처 공백 — Event.md 23-24줄의 "이벤트는 적용 대상 자식 요소들에게도 동일하게 발생되며 handler가 있다면 처리됨"은 전파 방향을 정하지 않아 모호하고, 28줄 "이벤트 진행 제어"는 제목만 있다. bubbling, capturing, stopPropagation, 이벤트 위임은 MDN DOM events 같은 공식 자료가 들어올 때 다룬다. ↩︎

  16. 출처 공백 — DOM.md (JavaScript) 9줄과 Event.md 8줄의 "event와 event listener"는 제목만 있다. 같은 노트 36줄 "event listener 등록 방식" 아래에는 inline 방식만 있다. ↩︎