 前端监听资源加载错误
前端监听资源加载错误
  # 前言
页面上有很多资源元素,比如 <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
