Skip to content

Commit c0d638a

Browse files
committed
minor fixes
1 parent 2f4747b commit c0d638a

File tree

1 file changed

+41
-37
lines changed

1 file changed

+41
-37
lines changed

2-ui/5-loading/02-script-async-defer/article.md

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Luckily, there are two `<script>` attributes that solve the problem for us: `def
3737

3838
## defer
3939

40-
The `defer` attribute tells the browser that it should go on working with the page, and load the script "in background", then run the script when it loads.
40+
The `defer` attribute tells the browser not to wait for the script. Instead, the browser will continue to process the HTML, build DOM. The script loads "in the background", and then runs when the DOM is fully built.
4141

4242
Here's the same example as above, but with `defer`:
4343

@@ -50,16 +50,18 @@ Here's the same example as above, but with `defer`:
5050
<p>...content after script...</p>
5151
```
5252

53+
In other words:
54+
5355
- Scripts with `defer` never block the page.
54-
- Scripts with `defer` always execute when the DOM is ready, but before `DOMContentLoaded` event.
56+
- Scripts with `defer` always execute when the DOM is ready (but before `DOMContentLoaded` event).
5557

56-
The following example demonstrates that:
58+
The following example demonstrates the second part:
5759

5860
```html run height=100
5961
<p>...content before scripts...</p>
6062

6163
<script>
62-
document.addEventListener('DOMContentLoaded', () => alert("DOM ready after defer!")); // (2)
64+
document.addEventListener('DOMContentLoaded', () => alert("DOM ready after defer!"));
6365
</script>
6466

6567
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
@@ -68,40 +70,44 @@ The following example demonstrates that:
6870
```
6971

7072
1. The page content shows up immediately.
71-
2. `DOMContentLoaded` waits for the deferred script. It only triggers when the script `(2)` is downloaded and executed.
73+
2. `DOMContentLoaded` event handler waits for the deferred script. It only triggers when the script is downloaded and executed.
7274

73-
Deferred scripts keep their relative order, just like regular scripts.
75+
**Deferred scripts keep their relative order, just like regular scripts.**
7476

75-
So, if we have a long script first, and then a smaller one, then the latter one waits.
77+
Let's say, we have two deferred scripts: the `long.js` and then `small.js`:
7678

7779
```html
7880
<script defer src="https://javascript.info/article/script-async-defer/long.js"></script>
7981
<script defer src="https://javascript.info/article/script-async-defer/small.js"></script>
8082
```
8183

82-
```smart header="The small script downloads first, runs second"
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+
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 finishes first.
8485

85-
But the specification requires scripts to execute in the document order, so it waits for `long.js` to execute.
86-
```
86+
...But the `defer` atribute, besides telling the browser "not to block", ensures that the relative order is kept. So even though `small.js` loads first, it still waits and runs after `long.js` executes.
87+
88+
That may be important for cases when we need to load a JavaScript library and then a script that depends on it.
8789

8890
```smart header="The `defer` attribute is only for external scripts"
8991
The `defer` attribute is ignored if the `<script>` tag has no `src`.
9092
```
9193
92-
9394
## async
9495
96+
The `async` attribute is somewhat like `defer`. It also makes the script non-blocking. But it has important differences in the behavior.
97+
9598
The `async` attribute means that a script is completely independent:
9699
97-
- The page doesn't wait for async scripts, the contents are processed and displayed.
100+
- The browser doesn't block on `async` scripts (like `defer`).
101+
- Other scripts don't wait for `async` scripts, and `async` scripts don't wait for them.
98102
- `DOMContentLoaded` and async scripts don't wait for each other:
99103
- `DOMContentLoaded` may happen both before an async script (if an async script finishes loading after the page is complete)
100104
- ...or after an async script (if an async script is short or was in HTTP-cache)
101-
- Other scripts don't wait for `async` scripts, and `async` scripts don't wait for them.
102105
106+
In other words, `async` scripts load in the background and run when ready. The DOM and other scripts don't wait for them, and they don't wait for anything. A fully independent script that runs when loaded. As simple, at it can get, right?
103107
104-
So, if we have several `async` scripts, they may execute in any order. Whatever loads first -- runs first:
108+
Here's an example similar to what we've seen with `defer`: two scripts `long.js` and `small.js`, but now with `async` instead of `defer`.
109+
110+
They don't wait for each other. Whatever loads first (probably `small.js`) -- runs first:
105111
106112
```html run height=100
107113
<p>...content before scripts...</p>
@@ -116,9 +122,9 @@ So, if we have several `async` scripts, they may execute in any order. Whatever
116122
<p>...content after scripts...</p>
117123
```
118124

119-
1. The page content shows up immediately: `async` doesn't block it.
120-
2. `DOMContentLoaded` may happen both before and after `async`, no guarantees here.
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.
125+
- The page content shows up immediately: `async` doesn't block it.
126+
- `DOMContentLoaded` may happen both before and after `async`, no guarantees here.
127+
- A smaller script `small.js` goes second, but probably loads before `long.js`, so `small.js` runs first. Although, it might be that `long.js` loads first, if cached, then it runs first. In other words, async scripts run in the "load-first" order.
122128

123129
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:
124130

@@ -127,10 +133,11 @@ Async scripts are great when we integrate an independent third-party script into
127133
<script async src="https://google-analytics.com/analytics.js"></script>
128134
```
129135

130-
131136
## Dynamic scripts
137+
138+
There's one more important way of adding a script to the page.
132139

133-
We can also add a script dynamically using JavaScript:
140+
We can create a script and append it to the document dynamically using JavaScript:
134141

135142
```js run
136143
let script = document.createElement('script');
@@ -146,20 +153,11 @@ That is:
146153
- They don't wait for anything, nothing waits for them.
147154
- The script that loads first -- runs first ("load-first" order).
148155

156+
This can be changed if we explicitly set `script.async=true`. Then scripts will be executed in the document order, just like `defer`.
149157

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-
For example, here we add two scripts. Without `script.async=false` they would execute in load-first order (the `small.js` probably first). But with that flag the order is "as in the document":
158+
In this example, `loadScript(src)` function adds a script and also sets `async` to `false`.
162159

160+
So `long.js` always runs first (as it's added first):
163161

164162
```js run
165163
function loadScript(src) {
@@ -174,6 +172,10 @@ loadScript("/article/script-async-defer/long.js");
174172
loadScript("/article/script-async-defer/small.js");
175173
```
176174

175+
Without `script.async=false`, scripts would execute in default, load-first order (the `small.js` probably first).
176+
177+
Again, as with the `defer`, the order matters if we'd like to load a library and then another script that depends on it.
178+
177179

178180
## Summary
179181

@@ -186,12 +188,14 @@ But there are also essential differences between them:
186188
| `async` | *Load-first order*. Their document order doesn't matter -- which loads first | Irrelevant. 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. |
187189
| `defer` | *Document order* (as they go in the document). | Execute after the document is loaded and parsed (they wait if needed), right before `DOMContentLoaded`. |
188190

191+
In practice, `defer` is used for scripts that need the whole DOM and/or their relative execution order is important.
192+
193+
And `async` is used for independent scripts, like counters or ads. And their relative execution order does not matter.
194+
189195
```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.
196+
Please note: if you're using `defer` or `async`, then user will see the the page *before* the script loads.
191197
192-
So the user may read the page, but some graphical components are probably not ready yet.
198+
In such case, some graphical components are probably not initialized yet.
193199
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.
200+
Don't forget to put "loading" indication and disable buttons that aren't functional yet. Let the user clearly see what he can do on the page, and what's still getting ready.
195201
```
196-
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

Comments
 (0)