52

前端监听资源加载错误

 6 years ago
source link: http://www.hongweipeng.com/index.php/archives/1608/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前言

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

这种做法的缺点:

<audio>, <video>

参考 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:DENY 响应的情况,由于请求响应是ok的,所以 contentWindow 不会为空。

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

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

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

完整代码如下:

document.addEventListener('load', function (event) {
  if (event) {
    var target = event.path[0]
    if(target.localName==='iframe'&&!target.contentWindow){
      //资源加载错误处理..
    } 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)

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK