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
Copy file name to clipboardExpand all lines: 2-ui/5-loading/01-onload-ondomcontentloaded/article.md
+22-23Lines changed: 22 additions & 23 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,13 +3,13 @@
3
3
The lifecycle of an HTML page has three important events:
4
4
5
5
-`DOMContentLoaded` -- the browser fully loaded HTML, and the DOM tree is built, but external resources like pictures `<img>` and stylesheets may be not yet loaded.
6
-
-`load` -- the browser loadedall resources (images, styles etc).
7
-
-`beforeunload/unload` -- when the user is leaving the page.
6
+
-`load` -- not only HTML is loaded, but also all the external resources: images, styles etc.
7
+
-`beforeunload/unload` -- the user is leaving the page.
8
8
9
9
Each event may be useful:
10
10
11
11
-`DOMContentLoaded` event -- DOM is ready, so the handler can lookup DOM nodes, initialize the interface.
12
-
-`load` event -- additional resources are loaded, we can get image sizes (if not specified in HTML/CSS) etc.
12
+
-`load` event -- external resources are loaded, so styles are applied, image sizes are known etc.
13
13
-`beforeunload` event -- the user is leaving: we can check if the user saved the changes and ask them whether they really want to leave.
14
14
-`unload` -- the user almost left, but we still can initiate some operations, such as sending out statistics.
15
15
@@ -49,7 +49,7 @@ In the example the `DOMContentLoaded` handler runs when the document is loaded,
49
49
50
50
But it doesn't wait for the image to load. So `alert` shows zero sizes.
51
51
52
-
At the first sight `DOMContentLoaded` event is very simple. The DOM tree is ready -- here's the event. There are few peculiarities though.
52
+
At first sight, the`DOMContentLoaded` event is very simple. The DOM tree is ready -- here's the event. There are few peculiarities though.
53
53
54
54
### DOMContentLoaded and scripts
55
55
@@ -60,7 +60,7 @@ So DOMContentLoaded definitely happens after such scripts:
@@ -73,11 +73,10 @@ So DOMContentLoaded definitely happens after such scripts:
73
73
74
74
In the example above, we first see "Library loaded...", and then "DOM ready!" (all scripts are executed).
75
75
76
-
```warn header="Scripts with `async`, `defer` or `type=\"module\"` don't block DOMContentLoaded"
77
-
78
-
Script attributes `async` and `defer`, that we'll cover [a bit later](info:script-async-defer), don't block DOMContentLoaded. [Javascript modules](info:modules) behave like `defer`, they don't block it too.
79
-
80
-
So here we're talking about "regular" scripts, like `<script>...</script>`, or `<script src="..."></script>`.
76
+
```warn header="Scripts that don't block DOMContentLoaded"
77
+
There are two exceptions from this rule:
78
+
1. Scripts with the `async` attribute, that we'll cover [a bit later](info:script-async-defer), don't block `DOMContentLoaded`.
79
+
2. Scripts that are generated dynamically with `document.createElement('script')` and then added to the webpage also don't block this event.
81
80
```
82
81
83
82
### DOMContentLoaded and styles
@@ -86,15 +85,15 @@ External style sheets don't affect DOM, so `DOMContentLoaded` does not wait for
86
85
87
86
But there's a pitfall. If we have a script after the style, then that script must wait until the stylesheet loads:
// the script doesn't not execute until the stylesheet is loaded
93
92
alert(getComputedStyle(document.body).marginTop);
94
93
</script>
95
94
```
96
95
97
-
The reason is that the script may want to get coordinates and other style-dependent properties of elements, like in the example above. Naturally, it has to wait for styles to load.
96
+
The reason for this is that the script may want to get coordinates and other style-dependent properties of elements, like in the example above. Naturally, it has to wait for styles to load.
98
97
99
98
As `DOMContentLoaded` waits for scripts, it now waits for styles before them as well.
100
99
@@ -109,13 +108,13 @@ So if `DOMContentLoaded` is postponed by long-loading scripts, then autofill als
109
108
110
109
## window.onload [#window-onload]
111
110
112
-
The `load` event on the `window` object triggers when the whole page is loaded including styles, images and other resources.
111
+
The `load` event on the `window` object triggers when the whole page is loaded including styles, images and other resources. This event is available via the `onload` property.
113
112
114
113
The example below correctly shows image sizes, because `window.onload` waits for all images:
115
114
116
115
```html run height=200 refresh
117
116
<script>
118
-
window.onload=function() {
117
+
window.onload=function() {// same as window.addEventListener('load', (event) => {
- We can send not only a string, but also forms and other formats, as described in the chapter <info:fetch-basics>, but usually it's a stringified object.
152
+
- We can send not only a string, but also forms and other formats, as described in the chapter <info:fetch>, but usually it's a stringified object.
154
153
- The data is limited by 64kb.
155
154
156
155
When the `sendBeacon` request is finished, the browser probably has already left the document, so there's no way to get server response (which is usually empty for analytics).
157
156
158
-
There's also a `keepalive` flag for doing such "after-page-left" requests in [fetch](info:fetch-basics) method for generic network requests. You can find more information in the chapter <info:fetch-api>.
157
+
There's also a `keepalive` flag for doing such "after-page-left" requests in [fetch](info:fetch) method for generic network requests. You can find more information in the chapter <info:fetch-api>.
159
158
160
159
161
-
If we want to cancel the transition to another page, we can't do it here. But we can use another event -- `onbeforeunload`.
160
+
If we want to cancel the transition to another page, we can't do it here. But we can use another event -- `onbeforeunload`.
For historical reasons, returning a non-empty string also counts as canceling the event. Some time ago browsers used show it as a message, but as the [modern specification](https://html.spec.whatwg.org/#unloading-documents) says, they shouldn't.
176
+
For historical reasons, returning a non-empty string also counts as canceling the event. Some time ago browsers used to show it as a message, but as the [modern specification](https://html.spec.whatwg.org/#unloading-documents) says, they shouldn't.
178
177
179
178
Here's an example:
180
179
@@ -218,7 +217,7 @@ if (document.readyState == 'loading') {
218
217
}
219
218
```
220
219
221
-
There's also `readystatechange` event that triggers when the state changes, so we can print all these states like this:
220
+
There's also the `readystatechange` event that triggers when the state changes, so we can print all these states like this:
222
221
223
222
```js run
224
223
// current state
@@ -273,12 +272,12 @@ The numbers in square brackets denote the approximate time of when it happens. E
273
272
274
273
Page load events:
275
274
276
-
- `DOMContentLoaded` event triggers on `document` when DOM is ready. We can apply JavaScript to elements at this stage.
275
+
- The `DOMContentLoaded` event triggers on `document` when the DOM is ready. We can apply JavaScript to elements at this stage.
277
276
- Script such as `<script>...</script>` or `<script src="..."></script>` block DOMContentLoaded, the browser waits for them to execute.
278
277
- Images and other resources may also still continue loading.
279
-
- `load` event on `window` triggers when the page and all resources are loaded. We rarely use it, because there's usually no need to wait for so long.
280
-
- `beforeunload` event on `window` triggers when the user wants to leave the page. If we cancel the event, browser asks whether the user really wants to leave (e.g we have unsaved changes).
281
-
- `unload` event on `window` triggers when the user is finally leaving, in the handler we can only do simple things that do not involve delays or asking a user. Because of that limitation, it's rarely used. We can send out a network request with `navigator.sendBeacon`.
278
+
- The `load` event on `window` triggers when the page and all resources are loaded. We rarely use it, because there's usually no need to wait for so long.
279
+
- The `beforeunload` event on `window` triggers when the user wants to leave the page. If we cancel the event, browser asks whether the user really wants to leave (e.g we have unsaved changes).
280
+
- The `unload` event on `window` triggers when the user is finally leaving, in the handler we can only do simple things that do not involve delays or asking a user. Because of that limitation, it's rarely used. We can send out a network request with `navigator.sendBeacon`.
282
281
- `document.readyState` is the current state of the document, changes can be tracked in the `readystatechange` event:
283
282
- `loading` -- the document is loading.
284
283
- `interactive` -- the document is parsed, happens at about the same time as `DOMContentLoaded`, but before it.
Copy file name to clipboardExpand all lines: 2-ui/5-loading/02-script-async-defer/article.md
+22-22Lines changed: 22 additions & 22 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,11 +3,11 @@
3
3
4
4
In modern websites, scripts are often "heavier" than HTML: their download size is larger, and processing time is also longer.
5
5
6
-
When the browser loads HTML and comes across a `<script>...</script>` tag, it can't continue building DOM. It must execute the script right now. The same happens for external scripts `<script src="..."></script>`: the browser must wait until the script downloads, execute it, and only after process the rest of the page.
6
+
When the browser loads HTML and comes across a `<script>...</script>` tag, it can't continue building the DOM. It must execute the script right now. The same happens for external scripts `<script src="..."></script>`: the browser must wait until the script downloads, execute it, and only after process the rest of the page.
7
7
8
8
That leads to two important issues:
9
9
10
-
1. Scripts can't see DOM elements below them, so can't add handlers etc.
10
+
1. Scripts can't see DOM elements below them, so they can't add handlers etc.
11
11
2. If there's a bulky script at the top of the page, it "blocks the page". Users can't see the page content till it downloads and runs:
12
12
13
13
```html run height=100
@@ -29,11 +29,11 @@ There are some workarounds to that. For instance, we can put a script at the bot
29
29
</body>
30
30
```
31
31
32
-
But this solution is far from perfect. For example, the browser actually notices the script (and can start downloading it) only after it downloaded the full HTML document. For long HTML documents, that may be a noticeable delay.
32
+
But this solution is far from perfect. For example, the browser notices the script (and can start downloading it) only after it downloaded the full HTML document. For long HTML documents, that may be a noticeable delay.
33
33
34
-
Such things are invisible for people using very fast connections, but many people in the world still have slower internet speeds and far-from-perfect mobile connectivity.
34
+
Such things are invisible for people using very fast connections, but many people in the world still have slow internet speeds and use a far-from-perfect mobile internet connection.
35
35
36
-
Luckily, there are two `<script>` attributes that solve the problem for us: `defer` and `async`
36
+
Luckily, there are two `<script>` attributes that solve the problem for us: `defer` and `async`.
37
37
38
38
## defer
39
39
@@ -68,34 +68,34 @@ The following example demonstrates that:
68
68
```
69
69
70
70
1. The page content shows up immediately.
71
-
2.`DOMContentLoaded` waits for the deferred script. It only triggers when the script `(2)` is downloaded is executed.
71
+
2.`DOMContentLoaded` waits for the deferred script. It only triggers when the script `(2)` is downloaded and executed.
72
72
73
73
Deferred scripts keep their relative order, just like regular scripts.
74
74
75
75
So, if we have a long script first, and then a smaller one, then the latter one waits.
```smart header="The small script downloads first, runs second"
83
83
Browsers scan the page for scripts and download them in parallel, to improve performance. So in the example above both scripts download in parallel. The `small.js` probably makes it first.
84
84
85
-
But the specification requres scripts to execute in the document order, so it waits for `long.js` to execute.
85
+
But the specification requires scripts to execute in the document order, so it waits for `long.js` to execute.
86
86
```
87
87
88
88
```smart header="The `defer` attribute is only for external scripts"
89
-
The `defer` attribute is ignored if the script has no `src`.
89
+
The `defer` attribute is ignored if the `<script>` tag has no `src`.
90
90
```
91
91
92
92
93
93
## async
94
94
95
-
The `async` attribute means that a script is completely independant:
95
+
The `async` attribute means that a script is completely independent:
96
96
97
-
- The page doesn't wait for async scripts, the contents is processed and displayed.
98
-
- `DOMContentLoaded` and async scripts don't wait each other:
97
+
- The page doesn't wait for async scripts, the contents are processed and displayed.
98
+
- `DOMContentLoaded` and async scripts don't wait for each other:
99
99
- `DOMContentLoaded` may happen both before an async script (if an async script finishes loading after the page is complete)
100
100
- ...or after an async script (if an async script is short or was in HTTP-cache)
101
101
- Other scripts don't wait for `async` scripts, and `async` scripts don't wait for them.
@@ -120,16 +120,17 @@ So, if we have several `async` scripts, they may execute in any order. Whatever
120
120
2.`DOMContentLoaded` may happen both before and after `async`, no guarantees here.
121
121
3. Async scripts don't wait for each other. A smaller script `small.js` goes second, but probably loads before `long.js`, so runs first. That's called a "load-first" order.
122
122
123
-
Async scripts are great when we integrate an independant third-party script into the page: counters, ads and so on.
123
+
Async scripts are great when we integrate an independent third-party script into the page: counters, ads and so on, as they don't depend on our scripts, and our scripts shouldn't wait for them:
124
124
125
125
```html
126
+
<!-- Google Analytics is usually added like this -->
Both `async` and `defer` have one common thing: they don't block page rendering. So the user can read page content and get acquanted with the page immediately.
180
+
Both `async` and `defer` have one common thing: downloading of such scripts doesn't block page rendering. So the user can read page content and get acquainted with the page immediately.
181
181
182
182
But there are also essential differences between them:
183
183
@@ -187,11 +187,11 @@ But there are also essential differences between them:
187
187
|`defer`|*Document order* (as they go in the document). | Execute after the document is loaded and parsed (they wait if needed), right before `DOMContentLoaded`. |
188
188
189
189
```warn header="Page without scripts should be usable"
190
-
Please note that if you're using `defer`, then the page is visible before the script loads and enables all the graphical components.
190
+
Please note that if you're using `defer`, then the page is visible *before* the script loads.
191
191
192
-
So, buttons should be disabled by CSS or by other means, to let the user
193
-
194
-
In practice, `defer` is used for scripts that need DOM and/or their relative execution order is important.
192
+
So the user may read the page, but some graphical components are probably not ready yet.
195
193
194
+
There should be "loading" indications in the proper places, and disabled buttons should show as such, so the user can clearly see what's ready and what's not.
195
+
```
196
196
197
-
So `async` is used for independent scripts, like counters or ads, that don't need to access page content. And their relative execution order does not matter.
197
+
In practice, `defer` is used for scripts that need the whole DOM and/or their relative execution order is important. And `async` is used for independent scripts, like counters or ads. And their relative execution order does not matter.
0 commit comments