资源加载:onload,onerror

优质
小牛编辑
136浏览
2023-12-01

浏览器允许我们跟踪外部资源的加载 —— 脚本,iframe,图片等。

这里有两个事件:

  • onload —— 成功加载,
  • onerror —— 出现 error。

加载脚本

假设我们需要加载第三方脚本,并调用其中的函数。

我们可以像这样动态加载它:

let script = document.createElement('script');
script.src = "my.js";

document.head.append(script);

……但如何运行在该脚本中声明的函数?我们需要等到该脚本加载完成,之后才能调用它。

请注意:

对于我们自己的脚本,可以使用 JavaScript module,但是它们并未被广泛应用于第三方库。

script.onload

我们的得力助手是 load 事件。它会在脚本加载并执行完成时触发。

例如:

let script = document.createElement('script');

// 可以从任意域(domain),加载任意脚本
script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"
document.head.append(script);

script.onload = function() {
  // 该脚本创建了一个变量 "_"
  alert( _.VERSION ); // 显示库的版本
};

因此,在 onload 中我们可以使用脚本中的变量,运行函数等。

……如果加载失败怎么办?例如,这里没有这样的脚本(error 404)或者服务器宕机(不可用)。

script.onerror

发生在脚本加载期间的 error 会被 error 事件跟踪到。

例如,我们请求一个不存在的脚本:

let script = document.createElement('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
};

请注意,在这里我们无法获取更多 HTTP error 的详细信息。我们不知道 error 是 404 还是 500 或者其他情况。只知道是加载失败了。

重要:

onload/onerror 事件仅跟踪加载本身。

在脚本处理和执行期间可能发生的 error 超出了这些事件跟踪的范围。也就是说:如果脚本成功加载,则即使脚本中有编程 error,也会触发 onload 事件。如果要跟踪脚本 error,可以使用 window.onerror 全局处理程序。

其他资源

loaderror 事件也适用于其他资源,基本上(basically)适用于具有外部 src 的任何资源。

例如:

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");
};

但是有一些注意事项:

  • 大多数资源在被添加到文档中后,便开始加载。但是 <img> 是个例外。它要等到获得 src (*) 后才开始加载。
  • 对于 <iframe> 来说,iframe 加载完成时会触发 iframe.onload 事件,无论是成功加载还是出现 error。

这是出于历史原因。

跨源策略

这里有一条规则:来自一个网站的脚本无法访问其他网站的内容。例如,位于 https://facebook.com 的脚本无法读取位于 https://gmail.com 的用户邮箱。

或者,更确切地说,一个源(域/端口/协议三者)无法获取另一个源(origin)的内容。因此,即使我们有一个子域,或者仅仅是另一个端口,这都是不同的源,彼此无法相互访问。

这个规则还影响其他域的资源。

如果我们使用的是来自其他域的脚本,并且该脚本中存在 error,那么我们无法获取 error 的详细信息。

例如,让我们使用一个脚本 error.js,该脚本只包含一个(错误)函数调用:

//