Skip to content

Commit 4161899

Browse files
authored
Update article.md
1 parent d811dff commit 4161899

1 file changed

Lines changed: 34 additions & 149 deletions

File tree

Lines changed: 34 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
# Resource loading: onload and onerror
1+
# 资源加载:onload onerror
22

3-
The browser allows to track the loading of external resources -- scripts, iframes, pictures and so on.
3+
浏览器允许跟踪外部资源的加载 —— 脚本、iframes、图像等。
44

5-
There are two events for it:
5+
有两个事件
66

7-
- `onload` -- successful load,
8-
- `onerror` -- an error occurred.
7+
- `onload` —— 成功加载,
8+
- `onerror` —— 发生异常。
99

10-
## Loading a script
10+
## 加载脚本
1111

12-
Let's say we need to load a third-party script and call a function that resides there.
12+
假设我们需要调用属于外部脚本的函数。
1313

14-
We can load it dynamically, like this:
14+
我们可以像这样动态加载:
1515

1616
```js
1717
let script = document.createElement('script');
@@ -20,187 +20,72 @@ script.src = "my.js";
2020
document.head.append(script);
2121
```
2222

23-
...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.
24-
25-
```smart
26-
For our own scripts we could use [JavaScript modules](info:modules) here, but they are not widely adopted by third-party libraries.
27-
```
23+
...但如何运行声明在脚本中的函数?我们需要等到脚本被加载后才能调用它。
2824

2925
### script.onload
3026

31-
The main helper is the `load` event. It triggers after the script was loaded and executed.
27+
主要得力于 `load` 事件。它在脚本被加载和执行后才被触发。
3228

33-
For instance:
29+
例如:
3430

3531
```js run untrusted
3632
let script = document.createElement('script');
3733

38-
// can load any script, from any domain
34+
// 可以从任意域名加载脚本
3935
script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"
4036
document.head.append(script);
4137

4238
*!*
4339
script.onload = function() {
44-
// the script creates a helper function "_"
45-
alert(_); // the function is available
40+
// 脚本创建了一个辅助函数 "_"
41+
alert(_); // 函数可用
4642
};
4743
*/!*
4844
```
4945

50-
So in `onload` we can use script variables, run functions etc.
46+
因此,在 `onload` 中我们使用脚本变量、运行函数等。
5147

52-
...And what if the loading failed? For instance, there's no such script (error 404) or the server or the server is down (unavailable).
48+
...如果加载失败怎么办?比如,没有这样的脚本(错误 404)或者服务器宕机(不可用)。
5349

5450
### script.onerror
5551

56-
Errors that occur during the loading of the script can be tracked on `error` event.
52+
发生在脚本(不是执行)期间的错误可以在 `error` 事件上进行追踪。
5753

58-
For instance, let's request a script that doesn't exist:
54+
比如,我们请求一个不存在的脚本:
5955

6056
```js run
6157
let script = document.createElement('script');
62-
script.src = "https://example.com/404.js"; // no such script
58+
script.src = "https://example.com/404.js"; // 没有这样的脚本
6359
document.head.append(script);
6460

6561
*!*
6662
script.onerror = function() {
67-
alert("Error loading " + this.src); // Error loading https://example.com/404.js
63+
alert("Error loading " + this.src); // 加载 https://example.com/404.js 发生错误
6864
};
6965
*/!*
7066
```
7167

72-
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.
73-
74-
```warn
75-
Events `onload`/`onerror` track only the loading itself.
76-
77-
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.
78-
```
79-
80-
## Other resources
81-
82-
The `load` and `error` events also work for other resources, basically for any resource that has an external `src`.
83-
84-
For example:
85-
86-
```js run
87-
let img = document.createElement('img');
88-
img.src = "https://js.cx/clipart/train.gif"; // (*)
89-
90-
img.onload = function() {
91-
alert(`Image loaded, size ${img.width}x${img.height}`);
92-
};
93-
94-
img.onerror = function() {
95-
alert("Error occurred while loading image");
96-
};
97-
```
98-
99-
There are some notes though:
100-
101-
- Most resources start loading when they are added to the document. But `<img>` is an exception. It starts loading when it gets an src `(*)`.
102-
- For `<iframe>`, the `iframe.onload` event triggers when the iframe loading finished, both for successful load and in case of an error.
103-
104-
That's for historical reasons.
105-
106-
## Crossorigin policy
107-
108-
There's a rule: scripts from one site can't access contents of the other site. So, e.g. a script at `https://facebook.com` can't read the user's mailbox at `https://gmail.com`.
109-
110-
Or, to be more precise, one origin (domain/port/protocol triplet) can't access the content from another one. So even if we have a subdomain, or just another port, these are different origins, no access to each other.
111-
112-
This rule also affects resources from other domains.
113-
114-
If we're using a script from another domain, and there's an error in it, we can't get error details.
115-
116-
For example, let's take a script with a single (bad) function call:
117-
```js
118-
// 📁 error.js
119-
noSuchFunction();
120-
```
121-
122-
Now load it from our domain:
68+
请注意,我们无法再这获取错误的更多细节。我们不知道错误是 404 还是 500 或者其他情况,只知道是加载失败了。
12369

124-
```html run height=0
125-
<script>
126-
window.onerror = function(message, url, line, col, errorObj) {
127-
alert(`${message}\n${url}, ${line}:${col}`);
128-
};
129-
</script>
130-
<script src="/article/onload-onerror/crossorigin/error.js"></script>
131-
```
132-
133-
We can see a good error report, like this:
134-
135-
```
136-
Uncaught ReferenceError: noSuchFunction is not defined
137-
https://javascript.info/article/onload-onerror/crossorigin/error.js, 1:1
138-
```
139-
140-
Now let's load the same script from another domain:
141-
142-
```html run height=0
143-
<script>
144-
window.onerror = function(message, url, line, col, errorObj) {
145-
alert(`${message}\n${url}, ${line}:${col}`);
146-
};
147-
</script>
148-
<script src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>
149-
```
150-
151-
The report is different, like this:
152-
153-
```
154-
Script error.
155-
, 0:0
156-
```
70+
## 其他资源
15771

158-
Details may vary depending on the browser, but the idea is same: any information about the internals of a script is hidden. Exactly because it's from another domain.
72+
`load``error` 事件也适用于其他资源。但是也存在细微的差别。
15973

160-
Why do we need the details?
74+
例如:
16175

162-
There are many services (and we can build our own) that listen to `window.onerror`, save errors at the server and provide an interface to access and analyze them. That's great, as we can see real errors, triggered by our users. But we can't see any error information for scripts from other domains.
163-
164-
Similar cross-origin policy (CORS) is enforced for other types of resources as well.
165-
166-
**To allow cross-origin access, we need `crossorigin` attribute, plus the remote server must provide special headers.**
167-
168-
There are three levels of cross-origin access:
169-
170-
1. **No `crossorigin` attribute** -- access prohibited.
171-
2. **`crossorigin="anonymous"`** -- access allowed if the server responds with the header `Access-Control-Allow-Origin` with `*` or our origin. Browser does not send authorization information and cookies to remote server.
172-
3. **`crossorigin="use-credentials"`** -- access allowed if the server sends back the header `Access-Control-Allow-Origin` with our origin and `Access-Control-Allow-Credentials: true`. Browser sends authorization information and cookies to remote server.
173-
174-
```smart
175-
You can read more about cross-origin access in the chapter <info:fetch-crossorigin>. It describes `fetch` method for network requests, but the policy is exactly the same.
176-
177-
Such thing as "cookies" is out of our current scope, but you can read about them in the chapter <info:cookie>.
178-
```
179-
180-
In our case, we didn't have any crossorigin attribute. So the cross-origin access was prohibited. Let's add it.
181-
182-
We can choose between `"anonymous"` (no cookies sent, one server-side header needed) and `"use-credentials"` (sends cookies too, two server-side headers needed).
183-
184-
If we don't care about cookies, then `"anonymous"` is a way to go:
185-
186-
```html run height=0
187-
<script>
188-
window.onerror = function(message, url, line, col, errorObj) {
189-
alert(`${message}\n${url}, ${line}:${col}`);
190-
};
191-
</script>
192-
<script *!*crossorigin="anonymous"*/!* src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>
193-
```
76+
`<img>``<link>`(外部样式表)
77+
: `load``error` 事件都如期运行。
19478

195-
Now, assuming that the server provides `Access-Control-Allow-Origin` header, everything's fine. We have the full error report.
79+
`<iframe>`
80+
: 只有当 iframe 加载完成时会发生 `load` 事件。在成功或失败的情况下,都会触发它。这是历史原因。
19681

197-
## Summary
82+
## 总结
19883

199-
Images `<img>`, external styles, scripts and other resources provide `load` and `error` events to track their loading:
84+
`<img>` 图像、外部样式表、脚本和其他资源都提供了 `load` `error` 事件来追踪它们的加载:
20085

201-
- `load` triggers on a successful load,
202-
- `error` triggers on a failed load.
86+
- `load` 在成功加载时被触发。
87+
- `error` 在加载失败时被触发。
20388

204-
The only exception is `<iframe>`: for historical reasons it always triggers `load`, for any load completion, even if the page is not found.
89+
只有 `<iframe>` 特殊:出于历史原因,即使页面没有被找到,它总会触发 `load` 来完成任何加载。
20590

206-
The `readystatechange` event also works for resources, but is rarely used, because `load/error` events are simpler.
91+
`readystatechange` 事件也适用于资源,但很少被使用,因为 `load/error` 事件更简单。

0 commit comments

Comments
 (0)