You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
모던 웹브라우저에서 돌아가는 스크립트들은 대부분 HTML보다 '무겁습니다'. 용량이 커서 다운로드받는 데 오랜 시간이 걸리고 처리하는 것 역시 마찬가지이죠.
5
5
6
-
브라우저는 HTML을 읽다가 `<script>...</script>` 태그를 만나면 스크립트를 먼저 실행해야 하므로 DOM 생성을 멈춥니다. 이는 외부 스크립트 `<script src="..."></script>`를 만났을 때도 마찬가지입니다. 외부에서 스크립트를 다운로드받고 실행한 후에야 나머지 페이지들을 처리할 수 있습니다.
6
+
브라우저는 HTML을 읽다가 `<script>...</script>` 태그를 만나면 스크립트를 먼저 실행해야 하므로 DOM 생성을 멈춥니다. 이는 `src` 속성이 있는 외부 스크립트 `<script src="..."></script>`를 만났을 때도 마찬가지입니다. 외부에서 스크립트를 다운받고 실행한 후에야 남은 페이지를 처리할 수 있습니다.
7
7
8
8
이런 브라우저의 동작 방식은 두 가지 중요한 이슈를 만듭니다.
9
9
10
-
1.스크립트는 스크립트 아래에 있는 DOM 요소를 볼 수 없습니다. 따라서 핸들러 추가 같은 여러 행위가 불가능해집니다.
11
-
2. 페이지 위쪽에 용량이 큰 스크립트가 있는 경우, 이 스크립트가 페이지를 '막아버립니다'. 페이지에 접속하는 사용자들은 스크립트를 다운받고 실행할 때까지 스크립트 아래쪽 페이지를 볼 수 없게 됩니다.
10
+
1.스크립트는에서 스크립트 아래에 있는 DOM 요소에 접근할 수 없습니다. 따라서 DOM 요소에 핸들러를 추가하는 것과 같은 여러 행위가 불가능해집니다.
11
+
2. 페이지 위쪽에 용량이 큰 스크립트가 있는 경우 스크립트가 페이지를 '막아버립니다'. 페이지에 접속하는 사용자들은 스크립트를 다운받고 실행할 때까지 스크립트 아래쪽 페이지를 볼 수 없게 됩니다.
이런 부작용들을 피할 수 있는 몇 가지 방법이 있습니다. 아래 예시처럼 스크립트를 페이지 맨 아래 놓는 것이 하나의 방법이 될 수 있죠. 이렇게 하면 스크립트에서 스크립트 위에 있는 요소를 볼 수 있습니다. 또한, 페이지 콘텐츠 출력을 막지 않게 됩니다.
22
+
이런 부작용들을 피할 수 있는 몇 가지 방법이 있습니다. 아래 예시처럼 스크립트를 페이지 맨 아래 놓는 것이 하나의 방법이 될 수 있죠. 이렇게 하면 스크립트 위에 있는 요소에 접근할 수 있습니다. 또한, 페이지 콘텐츠 출력을 막지 않게 됩니다.
23
23
24
24
```html
25
25
<body>
@@ -37,7 +37,7 @@
37
37
38
38
## defer
39
39
40
-
브라우저는 `defer` 속성이 있는 스크립트(이하 `defer` 스크립트 또는 지연 스크립트)를 '백그라운드'에서 불러옵니다. 실행은 페이지 로딩이 끝날 때까지 *지연* 되죠. `defer`스크립트를 만나도 HTML 파싱이 멈추지 않는 이유는 여기에 있습니다.
40
+
브라우저는 `defer` 속성이 있는 스크립트(이하 defer 스크립트 또는 지연 스크립트)를 '백그라운드'에서 다운로드 합니다. 따라서 지연 스크립트를 다운로드 하는 도중에도 HTML 파싱이 멈추지 않습니다. 그리고 `defer`스크립트 실행은 페이지 구성이 끝날 때까지 *지연* 됩니다.
41
41
42
42
위쪽 예시와 동일한 코드인데 스크립트에 `defer`만 붙여보겠습니다.
43
43
@@ -50,16 +50,16 @@
50
50
<p>...스크립트 뒤 콘텐츠...</p>
51
51
```
52
52
53
-
- 지연 스크립트는 HTML 파싱을 절대 막지 않습니다.
54
-
- 지연 스크립트는 DOM 트리가 완성된 후, `DOMContentLoaded`이벤트가 발생하기 전에 실행됩니다.
53
+
- 지연 스크립트는 페이지 생성을 절대 막지 않습니다.
54
+
- 지연 스크립트는 DOM이 준비된 후에 실행되긴 하지만 `DOMContentLoaded`이벤트 발생 전에 실행됩니다.
브라우저는 성능을 위해 페이지에 어떤 스크립트들이 있는지 스캔한 다음 스크립트를 병렬적으로 다운로드합니다. 따라서 위 예시의 스크립트 다운도 병렬적으로 진행되죠. `small.js` 다운로드가 `long.js`보다 빨리 끝날 수 있습니다.
83
+
브라우저는 성능을 위해 페이지에 어떤 스크립트들이 있는지 쭉 살펴본 후에야 스크립트를 병렬적으로 다운로드합니다. 위 예시에서도 스크립트 다운로드가 병렬적으로 진행되었습니다. 그런데 이 때 크기가 작은 `small.js`이 `long.js`보다 먼저 다운로드 될 수 있습니다.
84
84
85
-
그렇지만 명세서에서 스크립트를 문서에 추가된 순서대로 실행하라고 정의했기 때문에 `small.js`는 `long.js` 다음에 실행됩니다.
85
+
하지만 명세서에서 스크립트를 문서에 추가한 순서대로 실행하라고 정의했기 때문에 `small.js`는 `long.js` 다음에 실행됩니다.
86
86
```
87
87
88
88
```smart header="`defer` 속성은 외부 스크립트에만 유효합니다."
@@ -92,16 +92,16 @@
92
92
93
93
## async
94
94
95
-
`async` 속성은 스크립트가 완전히 독립적으로 행동할 수 있게 보장해 줍니다.
95
+
`async` 속성이 붙은 스크립트(이하 async 스크립트 또는 비동기 스크립트)는 페이지와 완전히 독립적으로 동작합니다.
96
96
97
-
- 페이지는 `async` 속성이 붙은 스크립트(이하 async 스크립트 또는 비동기 스크립트)를 기다리지 않고 페이지 내 콘텐츠를 처리, 출력합니다.
98
-
- `DOMContentLoaded`와 async 스크립트는 서로를 기다리지 않습니다.
99
-
- 페이지 구성이 끝나기 전에 `async` 스크립트 로딩이 끝난 경우, `DOMContentLoaded`는 async 스크립트 전에 발생할 수 있습니다,
100
-
- async 스크립트가 짧거나 HTTP 캐시 안에 있는 경우, `DOMContentLoaded`는 `async` 스크립트 후에도 발생할 수 있습니다.
97
+
- async 스크립트는 defer 스크립트와 마찬가지로 백그라운드에서 다운로드됩니다. 따라서 HTML 페이지는 async 스크립트 다운이 완료되길 기다리지 않고 페이지 내 콘텐츠를 처리, 출력합니다(하지만 async 스크립트 실행중에는 HTML 파싱이 멈춥니다 - 옮긴이).
98
+
- `DOMContentLoaded` 이벤트와 async 스크립트는 서로를 기다리지 않습니다.
99
+
- 페이지 구성이 끝난 후에 async 스크립트 다운로딩이 끝난 경우, `DOMContentLoaded`는 async 스크립트 실행 전에 발생할 수 있습니다,
100
+
- async 스크립트가 짧아서 페이지 구성이 끝나기 전에 다운로드 되거나 스크립트가 캐싱처리 된 경우, `DOMContentLoaded`는 `async` 스크립트 실행 후에 발생할 수도 있습니다.
101
101
- 다른 스크립트들은 `async` 스크립트를 기다리지 않습니다. `async` 스크립트 역시 다른 스크립트들을 기다리지 않습니다.
102
102
103
103
104
-
이런 특징 때문에 페이지에 `async` 스크립트가 여러 개 있는 경우, 그 실행 순서가 제각각이 됩니다. 먼저 로드되는 스크립트가 먼저 실행됩니다.
104
+
이런 특징 때문에 페이지에 `async` 스크립트가 여러 개 있는 경우, 그 실행 순서가 제각각이 됩니다. 실행은 다운로드가 끝난 스크립트 순으로 진행됩니다.
105
105
106
106
```html run height=100
107
107
<p>...스크립트 앞 콘텐츠...</p>
@@ -116,11 +116,11 @@
116
116
<p>...스크립트 뒤 콘텐츠...</p>
117
117
```
118
118
119
-
1.페이지 콘텐츠는 바로 출력됩니다. 비동기 스크립트는 페이지 로딩을 막지 않습니다.
120
-
2.`DOMContentLoaded` 이벤트는 비동기 스크립트 전이나 후에 실행됩니다. 순서에 보장이 없습니다.
121
-
3. 비동기 스크립트는 서로를 기다리지 않습니다. 위치상으론 `small.js`가 아래이긴 하지만 `long.js`보다 먼저 로드되었기 때문에 더 먼저 실행되었습니다. 이를 'load-first order'라고 부릅니다.
119
+
1.비동기 스크립트 다운로드는 페이지 로딩을 막지 않기 때문에 페이지 콘텐츠가 바로 출력됩니다.
120
+
2.`DOMContentLoaded` 이벤트는 상황에 따라 비동기 스크립트 전이나 후에 실행됩니다. 정확한 순서를 예측할 수 없습니다.
121
+
3. 비동기 스크립트는 서로를 기다리지 않습니다. 위치상으론 `small.js`가 아래이긴 하지만 `long.js`보다 먼저 다운로드되었기 때문에 먼저 실행됩니다. 이렇게 먼저 로드가 된 스크립트가 먼저 실행되는 것을 'load-first order'라고 부릅니다.
122
122
123
-
비동기 스크립트는 방문자 수 카운터나 광고 관련 스크립트같이 각각 독립적인 역할을 하는 서드 파티 스크립트를 현재 개발 중인 스크립트에 통합하려 할 때 아주 유용합니다. async 스크립트는 개발 중인 스크립트에 의존하지 않고, 그 반대도 마찬가지이기 때문입니다.
123
+
비동기 스크립트는 방문자 수 카운터나 광고 관련 스크립트처럼 각각 독립적인 역할을 하는 서드 파티 스크립트를 현재 개발 중인 스크립트에 통합하려 할 때 아주 유용합니다. async 스크립트는 개발 중인 스크립트에 의존하지 않고, 그 반대도 마찬가지이기 때문입니다.
124
124
125
125
```html
126
126
<!-- Google Analytics는 일반적으로 다음과 같이 삽입합니다. -->
@@ -130,42 +130,32 @@
130
130
131
131
## 동적 스크립트
132
132
133
-
자바스크립트를 사용하면 스크립트를 동적으로 추가할 수 있습니다(dynamic script).
133
+
자바스크립트를 사용하면 문서에 스크립트를 동적으로 추가할 수 있습니다. 이렇게 추가한 스크립트를 동적 스크립트(dynamic script)라고 부릅니다.
134
134
135
135
```js run
136
136
let script =document.createElement('script');
137
137
script.src="/article/script-async-defer/long.js";
138
138
document.body.append(script); // (*)
139
139
```
140
140
141
-
이렇게 추가한 동적 스크립트는 문서에 추가되자 마자(`(*)`로 표시한 줄) 스크립트 로딩이 시작됩니다.
141
+
위 예시에서 외부 스크립트는 관련 요소가 문서에 추가되자 마자(`(*)`로 표시한 줄) 다운로드가 시작됩니다.
142
142
143
-
**동적 스크립트는 기본적으로 'async' 스크립트처럼 행동합니다.**
143
+
그런데 **동적 스크립트는 기본적으로 'async' 스크립트처럼 행동합니다.**
144
144
145
-
따라서, 동적 스크립트는 다음과 같은 특징을 갖습니다.
146
-
- 그 어떤 것도 기다리지 않습니다. 다른 자원들도 동적 스크립트를 기다리지 않습니다.
147
-
- 먼저 로드된 스크립트가 먼저 실행됩니다('load-first order').
145
+
따라서 다음과 같은 특징을 갖습니다.
146
+
-동적 스크립트는 그 어떤 것도 기다리지 않습니다. 그리고 그 어떤 것도 동적 스크립트를 기다리지 않습니다.
147
+
- 먼저 다운로드된 스크립트가 먼저 실행됩니다('load-first' order).
148
148
149
-
150
-
```js run
151
-
let script =document.createElement('script');
152
-
script.src="/article/script-async-defer/long.js";
153
-
154
-
*!*
155
-
script.async=false;
156
-
*/!*
157
-
158
-
document.body.append(script);
159
-
```
160
-
161
-
아래 예시에선 두 개의 스크립트를 동적으로 문서에 추가합니다. `script.async=false`가 없었다면 이 두 스크립트는 'load-first order'로 실행됩니다. 크기가 작은 `small.js`가 먼저 실행되겠죠. 하지만 `script.async=false`가 있기 때문에 실행은 '문서에 추가된 순서'대로 됩니다.
149
+
아래 예시에선 두 스크립트를 동적으로 문서에 추가합니다. 그런데 `script.async=false`가 없었다면 이 스크립트들은 'load-first order'로 실행됩니다. 그럼 크기가 작은 `small.js`가 먼저 실행되겠죠. 하지만 `script.async=false`가 있기 때문에 실행은 '문서에 추가된 순서'대로 됩니다.
`async`와 `defer` 스크립트는 다운로드 시 페이지 렌더링을 막지 않는다는 공통점이 있습니다. 따라서 사용자는 오래 기다리지 않고도 페이지 콘텐츠를 볼 수 있습니다.
170
+
`async`와 `defer` 스크립트는 다운로드 시 페이지 렌더링을 막지 않는다는 공통점이 있습니다. 따라서 async와 defer를 적절히 사용하면 사용자가 오래 기다리지 않고 페이지 콘텐츠를 볼 수 있게 할 수 있습니다.
181
171
182
172
두 스크립트의 차이점은 다음과 같습니다.
183
173
184
-
|| 순서 |`DOMContentLoaded`|
174
+
|| 순서 | DOMContentLoaded |
185
175
|---------|---------|---------|
186
-
|`async`|*load-first order*. 문서 내 순서와 상관없이 먼저 로드된 스크립트가 먼저 실행됩니다. | 비동기 스크립트는 문서가 완전히 다운로드되지 않은 상태라도 로드 및 실행될 수 있습니다. 스크립트 크기가 작거나 캐싱 처리 되어있을 때 혹은 문서 길이가 아주 길 때 이런 일이 발생합니다. |
187
-
|`defer`|*문서에 추가된 순*| 지연 스크립트는 문서 로드와 파싱이 완료된 후에, `DOMContentLoaded` 이벤트 발생 전에 실행됩니다. |
176
+
|`async`|*load-first order*. 문서 내 순서와 상관없이 먼저 다운로드된 스크립트가 먼저 실행됩니다. | 비동기 스크립트는 HTML 문서가 완전히 다운로드되지 않은 상태라도 로드 및 실행될 수 있습니다. 스크립트 크기가 작거나 캐싱 처리 되어있을 때 혹은 HTML 문서 길이가 아주 길 때 이런 일이 발생합니다. |
177
+
|`defer`|*문서에 추가된 순*| 지연 스크립트는 문서 다운로드와 파싱이 완료된 후에, DOMContentLoaded 이벤트 발생 전에 실행됩니다. |
0 commit comments