前端监听资源加载错误

前端技巧 2018-09-14

前言

页面上有很多资源元素,比如<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>标签

此外几乎所有浏览器都支持onloadonerror,

这种做法的缺点:

  1. 每个要处理的元素都要绑定事件,html和js耦合太深,处理的脚本不能通用化、插件化,比如给另一个页面也能方便使用
  2. Windows 7 下的 Internet Explorer 11 不支持<audio>, <video>的 onerror 事件(我没试过。

参考JS错误监控总结一文,我们采用window.addEventListener("error",()=>{})的方法

window.addEventListener

window.addEventListener('error')与window.onerror的异同点在于:

  1. 前者能够捕获到资源加载错误,后者不能。
  2. 都能捕获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.path[0]
    // 对该资源进行处理..
  }
  //设为true表示捕获阶段调用,会在元素的onerror前调用
}, true)

上面说过,<iframe>支持 onload 不支持 onerror,故以上代码不会监听到iframe加载失败事件

此外,由于window.addEventListener('load')是监听文档是否加载完毕,故无法监听资源加载成功事件

最终方案: document.addEventListener

document.addEventListener 可以用来监听Element元素的加载情况

对于iframe来说,我们只能监听load.

至于判断是否加载成功,我们可以通过:event.path[0].contentWindow!==null来判断。

只要请求响应成功,该 contentWindow 就不会为null。

注意:对于设置了X-Frame-Options:DENYContent Security Policy的情况,由于请求响应是ok的,所以 contentWindow 不会为空。

这种情况是否属于资源加载错误属于产品层面定义。

若归类为加载错误,暂未找到好的解决方案。

同域的话可以访问 contetnDocument, 看里面内容是否为空(仅只有head和body标签)

但是加载成功失败与否,contentWindow 对象都存在。

对于同域 iframe 可以检查 contenDocument 的内容来判断

完整代码如下:

document.addEventListener('load', function (event) {
  if (event) {
    var target = event.path[0]
    if(target.localName==='iframe'){
      // 继续判断...
    } else{
      //资源加载成功处理..
    }
  }
}, true)
document.addEventListener('error', function (event) {
  if (event) {
    var target = event.path[0]
    // 资源加载错误处理.. target.outerHTML 拿到原标签内容,例 <img src="./img/a.png">
  }
  //设为true表示捕获阶段调用,会在元素的onerror前调用,在window.addEventListener('error')后调用
}, true)

本文由 GaHingZ 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

如果对您有用,您的支持将鼓励我继续创作!