diff --git a/1-js/13-modules/01-modules-intro/article.md b/1-js/13-modules/01-modules-intro/article.md index ad83d425..19601e16 100644 --- a/1-js/13-modules/01-modules-intro/article.md +++ b/1-js/13-modules/01-modules-intro/article.md @@ -226,7 +226,7 @@ You may want skip those for now if you're reading for the first time, or if you ### Module scripts are deferred -Module scripts are *always* deferred, same effect as `defer` attribute (described in the chapter [](info:onload-ondomcontentloaded)), for both external and inline scripts. +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 other words: - external module scripts `` 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. +When the browser processes an HTML-document and comes across a ` -### Scripts with `async` and `defer` + -Attributes `async` and `defer` work only for external scripts. They are ignored if there's no `src`. + +``` -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. +In the example above, we first see "Library loaded...", and then "DOM ready!" (all scripts are executed). -There are two differences between them. +```warn header="Scripts with `async`, `defer` or `type=\"module\"` don't block DOMContentLoaded" -| | `async` | `defer` | -|---------|---------|---------| -| 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). | -| `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`. | +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. -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. - -While `defer` is used for scripts that need DOM and/or their relative execution order is important. +So here we're talking about "regular" scripts, like ``, or ``. +``` ### DOMContentLoaded and styles -External style sheets don't affect DOM, and so `DOMContentLoaded` does not wait for them. +External style sheets don't affect DOM, so `DOMContentLoaded` does not wait for them. -But there's a pitfall: if we have a script after the style, then that script must wait for the stylesheet to execute: +But there's a pitfall. Isf we have a script after the style, then that script must wait until the stylesheet loads: ```html @@ -98,7 +106,6 @@ For instance, if the page has a form with login and password, and the browser re 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. -One of minor benefits in using `async` and `defer` for external scripts -- they don't block `DOMContentLoaded` and don't delay browser autofill. ## window.onload [#window-onload] @@ -123,15 +130,15 @@ The example below correctly shows image sizes, because `window.onload` waits for 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. -This event is a good place to send out analytics. +The notable exception is sending analytics. -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. +Let's say we gather data about how the page is used: mouse clicks, scrolls, viewed page areas, and so on. -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. +Naturally, `unload` event is when the user leaves us, and we'd like to save the data on our server. -So, there exist `navigator.sendBeacon(url, data)` method for such needs, described in the specification . +There exists a special `navigator.sendBeacon(url, data)` method for such needs, described in the specification . -It sends the data in background. The transition to another page is not delayed: the browser leaves the page and performs `sendBeacon` in background. +It sends the data in background. The transition to another page is not delayed: the browser leaves the page, but still performs `sendBeacon`. Here's how to use it: ```js @@ -148,15 +155,28 @@ window.addEventListener("unload", function() { 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). +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 . + + If we want to cancel the transition to another page, we can't do it here. But we can use another event -- `onbeforeunload`. ## window.onbeforeunload [#window.onbeforeunload] If a visitor initiated navigation away from the page or tries to close the window, the `beforeunload` handler asks for additional confirmation. -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. +If we cancel the event, the browser may ask the visitor if they are sure. -You can try it by running this code and then reloading the page. +You can try it by running this code and then reloading the page: + +```js run +window.onbeforeunload = function() { + return false; +}; +``` + +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. + +Here's an example: ```js run window.onbeforeunload = function() { @@ -164,11 +184,7 @@ window.onbeforeunload = function() { }; ``` -```online -Or you can click on the button in `