Skip to content

Commit 0873d43

Browse files
committed
up
1 parent 706b1f2 commit 0873d43

File tree

62 files changed

+1694
-141
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1694
-141
lines changed

1-js/13-modules/01-modules-intro/article.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ You may want skip those for now if you're reading for the first time, or if you
226226
227227
### Module scripts are deferred
228228
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.
230230
231231
In other words:
232232
- external module scripts `<script type="module" src="...">` don't block HTML processing.

2-ui/3-event-details/10-onload-ondomcontentloaded/article.md renamed to 2-ui/10-loading/01-onload-ondomcontentloaded/article.md

+65-47
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Page lifecycle: DOMContentLoaded, load, beforeunload, unload
1+
# Page: DOMContentLoaded, load, beforeunload, unload
22

33
The lifecycle of an HTML page has three important events:
44

@@ -10,7 +10,8 @@ Each event may be useful:
1010

1111
- `DOMContentLoaded` event -- DOM is ready, so the handler can lookup DOM nodes, initialize the interface.
1212
- `load` event -- additional resources are loaded, we can get image sizes (if not specified in HTML/CSS) etc.
13-
- `beforeunload/unload` event -- the user is leaving: we can check if the user saved the changes and ask them whether they really want to leave.
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+
- `unload` -- the user almost left, but we still can initiate some operations, such as sending out statistics.
1415

1516
Let's explore the details of these events.
1617

@@ -22,6 +23,7 @@ We must use `addEventListener` to catch it:
2223

2324
```js
2425
document.addEventListener("DOMContentLoaded", ready);
26+
// not "document.onDOMContentLoaded = ..."
2527
```
2628

2729
For instance:
@@ -43,40 +45,46 @@ For instance:
4345
<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">
4446
```
4547

46-
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.
4749

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.
4951

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.
5153

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
5355

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.
5557

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:
5759

58-
### Scripts with `async` and `defer`
60+
```html run
61+
<script>
62+
document.addEventListener("DOMContentLoaded", () => {
63+
console.log("DOM ready!");
64+
});
65+
</script>
5966

60-
Attributes `async` and `defer` work only for external scripts. They are ignored if there's no `src`.
67+
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"></script>
6168

62-
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+
```
6373

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).
6575

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"
7077

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.
7279

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+
```
7482
7583
### DOMContentLoaded and styles
7684
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.
7886
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:
8088
8189
```html
8290
<link type="text/css" rel="stylesheet" href="style.css">
@@ -98,7 +106,6 @@ For instance, if the page has a form with login and password, and the browser re
98106

99107
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.
100108

101-
One of minor benefits in using `async` and `defer` for external scripts -- they don't block `DOMContentLoaded` and don't delay browser autofill.
102109

103110
## window.onload [#window-onload]
104111

@@ -123,15 +130,15 @@ The example below correctly shows image sizes, because `window.onload` waits for
123130

124131
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.
125132

126-
This event is a good place to send out analytics.
133+
The notable exception is sending analytics.
127134

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.
129136

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.
131138

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/>.
133140

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`.
135142

136143
Here's how to use it:
137144
```js
@@ -148,37 +155,48 @@ window.addEventListener("unload", function() {
148155
149156
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).
150157
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+
151161
If we want to cancel the transition to another page, we can't do it here. But we can use another event -- `onbeforeunload`.
152162
153163
## window.onbeforeunload [#window.onbeforeunload]
154164
155165
If a visitor initiated navigation away from the page or tries to close the window, the `beforeunload` handler asks for additional confirmation.
156166
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.
158168
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:
160170
161171
```js run
162172
window.onbeforeunload = function() {
163-
return "There are unsaved changes. Leave now?";
173+
return false;
164174
};
165175
```
166176
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:
169180
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+
};
171185
```
172186
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+
173189
## readyState
174190
175191
What happens if we set the `DOMContentLoaded` handler after the document is loaded?
176192
177193
Naturally, it never runs.
178194
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.
180198
181-
The `document.readyState` property gives us information about it. There are 3 possible values:
199+
There are 3 possible values:
182200
183201
- `"loading"` -- the document is loading.
184202
- `"interactive"` -- the document was fully read.
@@ -192,13 +210,15 @@ Like this:
192210
function work() { /*...*/ }
193211

194212
if (document.readyState == 'loading') {
213+
// loading yet, wait for the event
195214
document.addEventListener('DOMContentLoaded', work);
196215
} else {
216+
// DOM is ready!
197217
work();
198218
}
199219
```
200220
201-
There's a `readystatechange` event that triggers when the state changes, so we can print all these states like this:
221+
There's also `readystatechange` event that triggers when the state changes, so we can print all these states like this:
202222
203223
```js run
204224
// current state
@@ -208,15 +228,14 @@ console.log(document.readyState);
208228
document.addEventListener('readystatechange', () => console.log(document.readyState));
209229
```
210230
211-
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.
212232
213-
What is the place of `readystatechange` among other events?
233+
Let's see the full events flow for the completeness.
214234
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:
216236
217237
```html
218238
<script>
219-
function log(text) { /* output the time and message */ }
220239
log('initial readyState:' + document.readyState);
221240

222241
document.addEventListener('readystatechange', () => log('readyState:' + document.readyState));
@@ -244,23 +263,22 @@ The typical output:
244263
6. [4] readyState:complete
245264
7. [4] window onload
246265
247-
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).
248267
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.
250269
- `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.
251270
252271
253-
## Lifecycle events summary
272+
## Summary
254273
255-
Page lifecycle events:
274+
Page load events:
256275
257276
- `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.
260278
- Images and other resources may also still continue loading.
261279
- `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`.
264282
- `document.readyState` is the current state of the document, changes can be tracked in the `readystatechange` event:
265283
- `loading` -- the document is loading.
266284
- `interactive` -- the document is parsed, happens at about the same time as `DOMContentLoaded`, but before it.

0 commit comments

Comments
 (0)