原文链接:http://javascript.info/onload-onerror,translate with ❤️ by zhangbao.
浏览器允许跟踪外部资源的加载——可以是脚本、iframe 或图片等。
有两个事件会发生:
onload
——加载成功,onerror
——加载出错。
加载脚本
假设我们需要调用外部脚本中的函数。
我们可以像这样动态加载:
let script = document.creatElement('script');
script.src = 'my.js';
document.head.append(script);
但是如何运行这个脚本中声明的函数呢?我们需要等到脚本加载完成,才可以调用。
script.onload
主要的帮手是 load
事件,它在脚本加载并且执行之后触发。
例如:
let script = document.creatElement('script');
// 可以从任何域名里加载任何脚本
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js';
document.head.append(script);
script.onload = function() {
// 脚本加载完毕后,就可以使用 Lodash 声明的函数“_”了
alert(_);
};
在 onload
中,我们可以使用脚本变量,执行脚本函数等。
但是,如果加载失败了怎么办?例如,脚本不存在(404 错误)或服务器宕机了(不可用)。
script.onerror
加载(而非执行)期间发生的错误可以使用 error
事件跟踪。
例如,我们请求一个不存在的脚本:
let script = document.createElement('script');
script.src = "https://example.com/404.js"; // 没有这个脚本
document.head.append(script);
script.onerror = function() {
console.log("加载出错 " + this.src); // 加载出错 https://example.com/404.js
};
需要注意的是,这里不能得到错误细节。我们不知道是 404 还是 500 什么错误,只知道是加载失败了。
其他资源
load
和 error
事件在其他外部资源上同样有效。不过,可能会有一些细微差别。
例如:
**、<link>**
(外部样式)
load
和 error
都能按照预期触发。
``
当 iframe 加载完成时,仅会触发 load
事件。加载成功或加载出错都触发这个事件。这是由于历史原因造成的。
总结
图片 <img>
、外部样式、脚本和其他资源提供了 load
和 error
事件来跟踪它们的加载:
load
——在载成功时触发,error
—— 加载失败时触发。
唯一的例外是 <iframe>
:由于历史原因,即使没有找到页面,它也会触发 load
事件,对于任何加载情况(成功或失败)都是如此。
readystatechange
事件也适用于这些资源,但很少使用,因为使用 load/error
事件更简单。
练习题
问题
一、带回调的图片加载
正常情况下,图片在创建时才加载。因此,当我们向页面添加 <img>
时,用户不会立即看到图片,浏览器首先要加载它。
为了能够立即显示图片,我们可以使用“高级”创建方式:
let img = document.createElement('img');
img.src = 'my.jpg';
浏览器开始加载图片并且保存于内存中。之后,当文档中出现相同地址的图片引用时(不管以何种方式),就会立即显示了。
创建函数 preloadImages(sources, callback)**,从 sources**
这个数组里加载所有图片,当加载完成了,执行回调函数 callback``。
例如,下面我们在图片加载完成后,alert
出加载成功的提示。
function loaded() {
alert("图片加载完成了")
}
preloadImages(["1.jpg", "2.jpg", "3.jpg"], loaded);
即使出错了,也要认为图片“加载了”,并执行函数。
也就是说,callback
不管所有图片是加载成功了还是失败了,都会调用。
这个函数还是挺有用的,例如,我们想要在所有图片加载好后,显示由多个可滚动图片组成的一个画廊。
在原文档中,你能看到供测试的图片链接,并且包含图片是否加载完成的判断代码,最终打印的结果应该是 300
。
答案
一、带回调的图片加载
解决思路:
根据每个资源路径创建
img
。为每个图片添加
onload
/onerror
处理程序。只要
onload
或onerror
触发了,就增加计数。当计数器的值等于资源数量时,就说明加载结束了:
callback()
。
function preloadImages(sources, callback) {
let counter = 0;
function onLoad() {
counter++;
if (counter == sources.length) callback();
}
for(let source of sources) {
let img = document.createElement('img');
img.onload = img.onerror = onLoad;
img.src = source;
}
}
(完)