From d811dffc73287f4cb2188e7f1dad7a102998c5c3 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Tue, 11 Jun 2019 16:13:45 +0800 Subject: [PATCH 01/33] Update article.md --- .../01-onload-ondomcontentloaded/article.md | 211 +++++++----------- 1 file changed, 83 insertions(+), 128 deletions(-) diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md index 322517af39..caef57c829 100644 --- a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md +++ b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md @@ -1,39 +1,37 @@ -# Page: DOMContentLoaded, load, beforeunload, unload +# 页面生命周期:DOMContentLoaded、load、beforeunload 和 unload -The lifecycle of an HTML page has three important events: +HTML 页面的生命周期有三个重要事件: -- `DOMContentLoaded` -- the browser fully loaded HTML, and the DOM tree is built, but external resources like pictures `` and stylesheets may be not yet loaded. -- `load` -- not only HTML is loaded, but also all the external resources: images, styles etc. -- `beforeunload/unload` -- the user is leaving the page. +- `DOMContentLoaded` —— 浏览器加载 HTML,并构建 DOM 树,但像 `` 和样式这样的资源可能还没有加载。 +- `load` —— 浏览器加载所有资源(图像,样式等)。 +- `beforeunload/unload` —— 当用户离开页面时。 -Each event may be useful: +每个事件都是有用的: -- `DOMContentLoaded` event -- DOM is ready, so the handler can lookup DOM nodes, initialize the interface. -- `load` event -- external resources are loaded, so styles are applied, image sizes are known etc. -- `beforeunload` event -- the user is leaving: we can check if the user saved the changes and ask them whether they really want to leave. -- `unload` -- the user almost left, but we still can initiate some operations, such as sending out statistics. +- `DOMContentLoaded` 事件 —— DOM 已经准备好,因此处理器可以查找 DOM 节点,并初始化接口。 +- `load` 事件 —— 额外资源被加载后,我们可以获取图像大小(如果在 HTML/CSS 中没有指定)等。 +- `beforeunload/unload` 事件 —— 用户即将离开:我们可以检查用户是否保存了修改,并在询问他是否真的要离开。 -Let's explore the details of these events. +我们探讨一下这些事件的细节。 ## DOMContentLoaded -The `DOMContentLoaded` event happens on the `document` object. +`DOMContentLoaded` 事件发生在 `document` 对象上。 -We must use `addEventListener` to catch it: +我们必须使用 `addEventListener` 来监听它: ```js document.addEventListener("DOMContentLoaded", ready); -// not "document.onDOMContentLoaded = ..." ``` -For instance: +例如: ```html run height=200 refresh ` 时,就会停止构建 DOM。它必须立即执行脚本。因此 `DOMContentLoaded` 只有在所有此类脚本被执行后才会发生。 -When the browser processes an HTML-document and comes across a ` +```smart header="A word about `async` and `defer`" +属性 `async`和 `defer` 仅适用于外部脚本。如果没有 `src`,它们就会被忽略。 - +这两种方法告诉浏览器,它可以继续解析页面,并“在后台”继续加载脚本,然后在外部脚本加载完成后执行它。因此脚本不会阻塞 DOM 的构建和页面的渲染。 - -``` - -In the example above, we first see "Library loaded...", and then "DOM ready!" (all scripts are executed). +他们之间有两个不同之处。 -```warn header="Scripts with `async`, `defer` or `type=\"module\"` don't block DOMContentLoaded" +| | `async` | `defer` | +|---------|---------|---------| +| Order | 具有 `async` 的脚本以**第一顺序被加载**。它们的文档顺序并不重要 —— 先加载先运行。 | 具有 `defer` 的脚本总是按照**文档顺序**来执行(就像它们在文档中那样)。 | +| `DOMContentLoaded` | 具有 `async` 的脚本可以在文档尚未完全下载时加载和执行。如果脚本较小或被缓存,而且文档足够长,就会发生这种情况。 | 在 `DOMContentLoaded` 之前,具有 `defer` 的脚本会在文档被加载并解析后执行(如果需要,它们会等待)。 | -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. +因此 `async` 用于完全独立的脚本。 -So here we're talking about "regular" scripts, like ``, or ``. ``` -### DOMContentLoaded and styles +### DOMContentLoaded 和样式 -External style sheets don't affect DOM, so `DOMContentLoaded` does not wait for them. +外部样式不会影响 DOM,因此 `DOMContentLoaded` 无需等待它们。 -But there's a pitfall. If we have a script after the style, then that script must wait until the stylesheet loads: +但有一个陷阱:如果在样式之后有一个脚本,那么该脚本必须等待样式被执行: ```html @@ -94,24 +85,25 @@ But there's a pitfall. If we have a script after the style, then that script mus ``` -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. +原因是脚本可能希望获取如上述示例所描述的元素坐标和其他与样式相关的属性。当然,它必须等待样式被加载。 -As `DOMContentLoaded` waits for scripts, it now waits for styles before them as well. +当 `DOMContentLoaded` 等待脚本时,它也在等待它们之前的样式。 -### Built-in browser autofill +### 浏览器内置填写 -Firefox, Chrome and Opera autofill forms on `DOMContentLoaded`. +Firefox、Chrome 和 Opera 都会在 `DOMContentLoaded` 中自动填写表单。 -For instance, if the page has a form with login and password, and the browser remembered the values, then on `DOMContentLoaded` it may try to autofill them (if approved by the user). +比如,如果页面有一个带有登录和密码的表单,并且浏览器记住了这些值,那么在 `DOMContentLoaded` 上,它就可以尝试自动填写它们(如果用户允许)。 -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. +因此如果 `DOMContentLoaded` 被长加载脚本延迟,那么自动填写也在等待。你可能在某些站点上(如果你使用浏览器自动填写)—— 登录/密码字段将不会立即自动填写,在页面被完全加载前会出现延迟。这实际上是延迟到 `DOMContentLoaded` 事件。 +为外部脚本使用 `async` 和 `defer` 的一个好处是 —— 它们不会阻塞 `DOMContentLoaded`,而且也不会延迟浏览器的自动填写。 ## window.onload [#window-onload] -The `load` event on the `window` object triggers when the whole page is loaded including styles, images and other resources. +当包括样式、图像和其他资源的页面被全部加载时,`load` 事件就会在 `window` 对象上被触发。 -The example below correctly shows image sizes, because `window.onload` waits for all images: +以下示例正确地显示了图像大小,因为 `window.onload` 等待了所有的图像: ```html run height=200 refresh ``` -The working example is [in the sandbox](sandbox:readystate). +[在 sandbox](sandbox:readystate) 中的运行示例。 -The typical output: +典型输出: 1. [1] initial readyState:loading 2. [2] readyState:interactive 3. [2] DOMContentLoaded 4. [3] iframe onload -5. [4] img onload -6. [4] readyState:complete +5. [4] readyState:complete +6. [4] img onload 7. [4] window onload -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). +方括号中的数字表示发生这种情况的大致时间。实际时间会长一些,但标记为相同数字的事件几乎是同时发生的(+- 几毫秒)。 -- `document.readyState` becomes `interactive` right before `DOMContentLoaded`. These two things actually mean the same. -- `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. +- `document.readyState` 在 `DOMContentLoaded` 之前会立即变成了 `interactive`。这两个事件的意义没有任何差别。 +- 当所有资源(`iframe` 和 `img`)都被加载后,`document.readyState` 变成了 `complete`。这里我们可以发现,它大约发生在 `img.onload` (`img` 是最后的资源) 和 `window.onload` 之间。转换到 `complete` 状态的意义与 `window.onload` 一致。区别在于 `window.onload` 在所有其他 `load` 处理器之后一直有效。 -## Summary +## 总结 -Page load events: +页面生命周期事件: -- `DOMContentLoaded` event triggers on `document` when DOM is ready. We can apply JavaScript to elements at this stage. - - Script such as `` or `` block DOMContentLoaded, the browser waits for them to execute. - - Images and other resources may also still continue loading. -- `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. -- `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). -- `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`. -- `document.readyState` is the current state of the document, changes can be tracked in the `readystatechange` event: - - `loading` -- the document is loading. - - `interactive` -- the document is parsed, happens at about the same time as `DOMContentLoaded`, but before it. - - `complete` -- the document and resources are loaded, happens at about the same time as `window.onload`, but before it. +- 当 DOM 准备就绪时,`DOMContentLoaded` 事件就会在 `document` 上触发。在这个阶段,我们可以将 JavaScript 应用于元素。 + - 除了 `async` 或 `defer` 的脚本外,所有的脚本都会被执行。 + - 图像和其他资源仍然可以继续被加载。 +- 当页面和所有资源被加载时,`load` 事件会在 `window` 上被触发。我们很少使用它,因为通常没有必要去等待那么久。 +- 当用户想要离开页面时,`beforeunload` 事件会在 `window` 上被触发。如果他返回一个字符串,那么浏览器就会以问题的形式向用户确认是否真的要离开。 +- 当用户最终离开时,`unload` 事件会在 `window` 上被触发,在处理器中,我们只能做一些简单的事情,不会涉及到延迟或询问用户。正是由于这个限制,它很少被使用。 +- `document.readyState` 是文档的当前状态,可以在 `readystatechange` 事件中跟踪变更: + - `loading` —— 文档正在被加载。 + - `interactive` —— 文档被解析,大概是与 `DOMContentLoaded` 同时发生,而不是在它之前发生。 + - `complete` —— 文档和资源被加载,与 `window.onload` 同时发生,而不是在它之前发生。 From 416189916ff48935d9115f0632c53ce2b7935c62 Mon Sep 17 00:00:00 2001 From: LeviDing Date: Tue, 11 Jun 2019 16:15:22 +0800 Subject: [PATCH 02/33] Update article.md --- 2-ui/5-loading/03-onload-onerror/article.md | 183 ++++---------------- 1 file changed, 34 insertions(+), 149 deletions(-) diff --git a/2-ui/5-loading/03-onload-onerror/article.md b/2-ui/5-loading/03-onload-onerror/article.md index ef1f5fe152..368b95eb11 100644 --- a/2-ui/5-loading/03-onload-onerror/article.md +++ b/2-ui/5-loading/03-onload-onerror/article.md @@ -1,17 +1,17 @@ -# Resource loading: onload and onerror +# 资源加载:onload 和 onerror -The browser allows to track the loading of external resources -- scripts, iframes, pictures and so on. +浏览器允许跟踪外部资源的加载 —— 脚本、iframes、图像等。 -There are two events for it: +有两个事件 -- `onload` -- successful load, -- `onerror` -- an error occurred. +- `onload` —— 成功加载, +- `onerror` —— 发生异常。 -## Loading a script +## 加载脚本 -Let's say we need to load a third-party script and call a function that resides there. +假设我们需要调用属于外部脚本的函数。 -We can load it dynamically, like this: +我们可以像这样动态加载: ```js let script = document.createElement('script'); @@ -20,187 +20,72 @@ script.src = "my.js"; document.head.append(script); ``` -...But how to run the function that is declared inside that script? We need to wait until the script loads, and only then we can call it. - -```smart -For our own scripts we could use [JavaScript modules](info:modules) here, but they are not widely adopted by third-party libraries. -``` +...但如何运行声明在脚本中的函数?我们需要等到脚本被加载后才能调用它。 ### script.onload -The main helper is the `load` event. It triggers after the script was loaded and executed. +主要得力于 `load` 事件。它在脚本被加载和执行后才被触发。 -For instance: +例如: ```js run untrusted let script = document.createElement('script'); -// can load any script, from any domain +// 可以从任意域名加载脚本 script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js" document.head.append(script); *!* script.onload = function() { - // the script creates a helper function "_" - alert(_); // the function is available + // 脚本创建了一个辅助函数 "_" + alert(_); // 函数可用 }; */!* ``` -So in `onload` we can use script variables, run functions etc. +因此,在 `onload` 中我们使用脚本变量、运行函数等。 -...And what if the loading failed? For instance, there's no such script (error 404) or the server or the server is down (unavailable). +...如果加载失败怎么办?比如,没有这样的脚本(错误 404)或者服务器宕机(不可用)。 ### script.onerror -Errors that occur during the loading of the script can be tracked on `error` event. +发生在脚本(不是执行)期间的错误可以在 `error` 事件上进行追踪。 -For instance, let's request a script that doesn't exist: +比如,我们请求一个不存在的脚本: ```js run let script = document.createElement('script'); -script.src = "https://example.com/404.js"; // no such script +script.src = "https://example.com/404.js"; // 没有这样的脚本 document.head.append(script); *!* script.onerror = function() { - alert("Error loading " + this.src); // Error loading https://example.com/404.js + alert("Error loading " + this.src); // 加载 https://example.com/404.js 发生错误 }; */!* ``` -Please note that we can't get HTTP error details here. We don't know was it error 404 or 500 or something else. Just that the loading failed. - -```warn -Events `onload`/`onerror` track only the loading itself. - -Errors during script processing and execution are out of the scope of these events. To track script errors, one can use `window.onerror` global handler. -``` - -## Other resources - -The `load` and `error` events also work for other resources, basically for any resource that has an external `src`. - -For example: - -```js run -let img = document.createElement('img'); -img.src = "https://js.cx/clipart/train.gif"; // (*) - -img.onload = function() { - alert(`Image loaded, size ${img.width}x${img.height}`); -}; - -img.onerror = function() { - alert("Error occurred while loading image"); -}; -``` - -There are some notes though: - -- Most resources start loading when they are added to the document. But `` is an exception. It starts loading when it gets an src `(*)`. -- For `