前端监听资源加载错误
# 前言
页面上有很多资源元素,比如 <img>
,<iframe>
等,我们需要知道其加载情况,根据加载成功与否进行下一步的处理。
常见的做法是给这些元素上设置 onload
,onerror
方法。
比如:<img onerror="errFn()" onload="loadFn()">
支持
onload
的标签:<body>, <frame>, <frameset>, <iframe>, <img>, <input type="image">, <link>, <script>, <style>
支持
onerror
的标签:<img>, <input type="image">, <object>, <script>, <style> , <audio>, <video>
注意IE9.0及以上才支持 <audio>, <video>
标签
此外几乎所有浏览器都支持 onload
和 onerror
,
这种做法的缺点:
- 每个要处理的元素都要绑定事件,html和js耦合太深,处理的脚本不能通用化、插件化,比如给另一个页面也能方便使用
- Windows 7 下的 Internet Explorer 11 不支持
<audio>, <video>
的 onerror 事件(我没试过。
# window.addEventListener
window.addEventListener('error')
与window.onerror的异同点在于:
- 前者能够捕获到资源加载错误,后者不能。
- 都能捕获js运行时错误,捕获到的错误参数不同。前者参数为一个event对象;后者为 msg, url, lineNo, columnNo, error一系列参数。event对象中都含有后者参数的信息。
用法如下:
window.addEventListener('error', function (event) {
console.log(event)
if (event) {
var target = event.target || event.srcElement;
// 写上
var isElementTarget = target instanceof HTMLElement
if (!isElementTarget) return; // js error不再处理
var source = event.target
// 对该资源进行处理..
}
//设为true表示捕获阶段调用,会在元素的onerror前调用
}, true)
2
3
4
5
6
7
8
9
10
11
12
13
上面说过,<iframe>
支持 onload 不支持 onerror,故以上代码不会监听到iframe加载失败事件
此外,由于window.addEventListener('load')
是监听文档是否加载完毕,故无法监听资源加载成功事件
# 最终方案: document.addEventListener
document.addEventListener
可以用来监听Element元素
的加载情况
对于iframe来说,我们只能监听load.
注意
至于判断是否加载成功,我们可以通过:event.target.contentWindow!==null
来判断。
只要请求响应成功,该 contentWindow 就不会为null。
注意:对于设置了X-Frame-Options:DENY
或Content Security Policy
的情况,由于请求响应是ok的,所以 contentWindow 不会为空。
这种情况是否属于资源加载错误属于产品层面定义。
若归类为加载错误,暂未找到好的解决方案。
同域的话可以访问 contetnDocument, 看里面内容是否为空(仅只有head和body标签) 但是加载成功失败与否,contentWindow 对象都存在。
对于同域 iframe 可以检查 contenDocument 的内容来判断
完整代码如下:
document.addEventListener('load', function (event) {
if (event) {
var target = event.target
if(target.localName==='iframe'){
// 继续判断...
} else{
//资源加载成功处理..
}
}
}, true)
document.addEventListener('error', function (event) {
if (event) {
var target = event.target
// 资源加载错误处理.. target.outerHTML 拿到原标签内容,例 <img src="./img/a.png">
}
//设为true表示捕获阶段调用,会在元素的onerror前调用,在window.addEventListener('error')后调用
}, true)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17