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: 1-js/13-modules/01-modules-intro/article.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -226,7 +226,7 @@ You may want skip those for now if you're reading for the first time, or if you
226
226
227
227
### Module scripts are deferred
228
228
229
-
Module scripts are *always* deferred, same effect as `defer` attribute (described in the chapter [](info:onload-ondomcontentloaded)), for both external and inline scripts.
229
+
Module scripts are *always* deferred, same effect as `defer` attribute (described in the chapter [](info:script-async-defer)), for both external and inline scripts.
In the example the `DOMContentLoaded` handler runs when the document is loaded and does not wait for the image to load. So `alert` shows zero sizes.
48
+
In the example the `DOMContentLoaded` handler runs when the document is loaded, so it can see all the elements, including `<img>` below.
47
49
48
-
At the first sight `DOMContentLoaded` event is very simple. The DOM tree is ready -- here's the event. But there are few peculiarities.
50
+
But it doesn't wait for the image to load. So `alert` shows zero sizes.
49
51
50
-
### DOMContentLoaded and scripts
52
+
At the first sight `DOMContentLoaded` event is very simple. The DOM tree is ready -- here's the event. There are few peculiarities though.
51
53
52
-
When the browser initially loads HTML and comes across a `<script>...</script>` in the text, it can't continue building DOM. It must execute the script right now. So `DOMContentLoaded` may only happen after all such scripts are executed.
54
+
### DOMContentLoaded and scripts
53
55
54
-
External scripts (with `src`) also put DOM building to pause while the script is loading and executing. So `DOMContentLoaded` waits for external scripts as well.
56
+
When the browser processes an HTML-document and comes across a `<script>` tag, it needs to execute before continuing building the DOM. That's a precaution, as scripts may want to modify DOM, and even `document.write` into it, so `DOMContentLoaded` has to wait.
55
57
56
-
The only exception are external scripts with `async` and `defer` attributes. They tell the browser to continue processing without waiting for the scripts. This lets the user see the page before scripts finish loading, which is good for performance.
58
+
So DOMContentLoaded definitely happens after such scripts:
Both of them tell the browser that it may go on working with the page, and load the script "in background", then run the script when it loads. So the script doesn't block DOM building and page rendering.
69
+
<script>
70
+
alert("Library loaded, inline script executed");
71
+
</script>
72
+
```
63
73
64
-
There are two differences between them.
74
+
In the example above, we first see "Library loaded...", and then "DOM ready!" (all scripts are executed).
65
75
66
-
||`async`|`defer`|
67
-
|---------|---------|---------|
68
-
| Order | Scripts with `async` execute *in the load-first order*. Their document order doesn't matter -- which loads first runs first. | Scripts with `defer` always execute *in the document order* (as they go in the document). |
69
-
|`DOMContentLoaded`| Scripts with `async` may load and execute while the document has not yet been fully downloaded. That happens if scripts are small or cached, and the document is long enough. | Scripts with `defer` execute after the document is loaded and parsed (they wait if needed), right before `DOMContentLoaded`. |
76
+
```warn header="Scripts with `async`, `defer` or `type=\"module\"` don't block DOMContentLoaded"
70
77
71
-
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.
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.
72
79
73
-
While `defer` is used for scripts that need DOM and/or their relative execution order is important.
80
+
So here we're talking about "regular" scripts, like `<script>...</script>`, or `<script src="..."></script>`.
81
+
```
74
82
75
83
### DOMContentLoaded and styles
76
84
77
-
External style sheets don't affect DOM, and so `DOMContentLoaded` does not wait for them.
85
+
External style sheets don't affect DOM, so `DOMContentLoaded` does not wait for them.
78
86
79
-
But there's a pitfall: if we have a script after the style, then that script must wait for the stylesheet to execute:
87
+
But there's a pitfall. Isf we have a script after the style, then that script must wait until the stylesheet loads:
@@ -98,7 +106,6 @@ For instance, if the page has a form with login and password, and the browser re
98
106
99
107
So if `DOMContentLoaded` is postponed by long-loading scripts, then autofill also awaits. You probably saw that on some sites (if you use browser autofill) -- the login/password fields don't get autofilled immediately, but there's a delay till the page fully loads. That's actually the delay until the `DOMContentLoaded` event.
100
108
101
-
One of minor benefits in using `async` and `defer` for external scripts -- they don't block `DOMContentLoaded` and don't delay browser autofill.
102
109
103
110
## window.onload [#window-onload]
104
111
@@ -123,15 +130,15 @@ The example below correctly shows image sizes, because `window.onload` waits for
123
130
124
131
When a visitor leaves the page, the `unload` event triggers on `window`. We can do something there that doesn't involve a delay, like closing related popup windows.
125
132
126
-
This event is a good place to send out analytics.
133
+
The notable exception is sending analytics.
127
134
128
-
E.g. we have a script that gathers some data about mouse clicks, scrolls, viewed page areas -- the statistics that can help us to see what users want.
135
+
Let's say we gather data about how the page is used: mouse clicks, scrolls, viewed page areas, and so on.
129
136
130
-
Then `onunload`is the best time to send it out. Regular networking methods such as [fetch](info:fetch-basics) or [XMLHttpRequest](info:xmlhttprequest) don't work well, because we're in the process of leaving the page.
137
+
Naturally, `unload` event is when the user leaves us, and we'd like to save the data on our server.
131
138
132
-
So, there exist`navigator.sendBeacon(url, data)` method for such needs, described in the specification <https://w3c.github.io/beacon/>.
139
+
There exists a special`navigator.sendBeacon(url, data)` method for such needs, described in the specification <https://w3c.github.io/beacon/>.
133
140
134
-
It sends the data in background. The transition to another page is not delayed: the browser leaves the page and performs `sendBeacon` in background.
141
+
It sends the data in background. The transition to another page is not delayed: the browser leaves the page, but still performs `sendBeacon`.
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).
150
157
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>.
159
+
160
+
151
161
If we want to cancel the transition to another page, we can't do it here. But we can use another event -- `onbeforeunload`.
152
162
153
163
## window.onbeforeunload [#window.onbeforeunload]
154
164
155
165
If a visitor initiated navigation away from the page or tries to close the window, the `beforeunload` handler asks for additional confirmation.
156
166
157
-
It may return a string with the question. Historically browsers used to show it, but as of now only some of them do. That's because certain webmasters abused this event handler by showing misleading and hackish messages.
167
+
If we cancel the event, the browser may ask the visitor if they are sure.
158
168
159
-
You can try it by running this code and then reloading the page.
169
+
You can try it by running this code and then reloading the page:
160
170
161
171
```js run
162
172
window.onbeforeunload=function() {
163
-
return"There are unsaved changes. Leave now?";
173
+
returnfalse;
164
174
};
165
175
```
166
176
167
-
```online
168
-
Or you can click on the button in`<iframe>` below to set the handler, and then click the link:
177
+
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.
178
+
179
+
Here's an example:
169
180
170
-
[iframe src="window-onbeforeunload" border="1" height="80" link edit]
181
+
```js run
182
+
window.onbeforeunload=function() {
183
+
return"There are unsaved changes. Leave now?";
184
+
};
171
185
```
172
186
187
+
The behavior was changed, because some webmasters abused this event handler by showing misleading and annoying messages. So right now old browsers still may show it as a message, but aside of that -- there's no way to customize the message shown to the user.
188
+
173
189
## readyState
174
190
175
191
What happens if we set the `DOMContentLoaded` handler after the document is loaded?
176
192
177
193
Naturally, it never runs.
178
194
179
-
There are cases when we are not sure whether the document is ready or not, for instance an external script with `async` attribute loads and runs asynchronously. Depending on the network, it may load and execute before the document is complete or after that, we can't be sure. So we should be able to know the current state of the document.
195
+
There are cases when we are not sure whether the document is ready or not. We'd like our function to execute when the DOM is loaded, be it now or later.
196
+
197
+
The `document.readyState` property tells us about the current loading state.
180
198
181
-
The `document.readyState` property gives us information about it. There are 3 possible values:
The `readystatechange` event is an alternative mechanics of tracking the document loading state, it appeared long ago. Nowadays, it is rarely used, but let's cover it for completeness.
231
+
The `readystatechange` event is an alternative mechanics of tracking the document loading state, it appeared long ago. Nowadays, it is rarely used.
212
232
213
-
What is the place of `readystatechange` among other events?
233
+
Let's see the full events flow for the completeness.
214
234
215
-
To see the timing, here's a document with `<iframe>`, `<img>` and handlers that log events:
235
+
Here's a document with `<iframe>`, `<img>` and handlers that log events:
216
236
217
237
```html
218
238
<script>
219
-
functionlog(text) { /* output the time and message */ }
The numbers in square brackets denote the approximate time of when it happens. The real time is a bit greater, but events labeled with the same digit happen approximately at the same time (+- a few ms).
266
+
The numbers in square brackets denote the approximate time of when it happens. Events labeled with the same digit happen approximately at the same time (+- a few ms).
248
267
249
-
- `document.readyState` becomes `interactive` right before `DOMContentLoaded`. These two events actually mean the same.
268
+
- `document.readyState` becomes `interactive` right before `DOMContentLoaded`. These two things actually mean the same.
250
269
- `document.readyState` becomes `complete` when all resources (`iframe` and `img`) are loaded. Here we can see that it happens in about the same time as `img.onload` (`img` is the last resource) and `window.onload`. Switching to `complete` state means the same as `window.onload`. The difference is that `window.onload` always works after all other `load` handlers.
251
270
252
271
253
-
## Lifecycle events summary
272
+
## Summary
254
273
255
-
Page lifecycle events:
274
+
Page load events:
256
275
257
276
- `DOMContentLoaded` event triggers on `document` when DOM is ready. We can apply JavaScript to elements at this stage.
258
-
- All inline scripts and scripts with `defer` are already executed.
259
-
- Async scripts may execute both before and after the event, depends on when they load.
277
+
- Script such as `<script>...</script>` or `<script src="..."></script>` block DOMContentLoaded, the browser waits for them to execute.
260
278
- Images and other resources may also still continue loading.
261
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.
262
-
- `beforeunload` event on `window` triggers when the user wants to leave the page. If it returns a string, the browser shows a question whether the user really wants to leave or not.
263
-
- `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.
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`.
264
282
- `document.readyState` is the current state of the document, changes can be tracked in the `readystatechange` event:
265
283
- `loading` -- the document is loading.
266
284
- `interactive` -- the document is parsed, happens at about the same time as `DOMContentLoaded`, but before it.
0 commit comments