为什么Chrome的img元素的onerror事件只会触发一次?

9

为什么当所有其他浏览器(IE7,8,9, FF, Opera和Safari)重复调用img元素的onerror事件时,Chrome只调用一次?

是否有一种方法可以强制Chrome再次重复调用onerror事件?

jsfiddle

HTML:

<div id="thisWorks">
    this works in Chrome. onerror event is called once.
    <img src="http://www.asdfjklasdfasdf.com/bogus1.png" 
        onerror="fixit(this);" 
        rsrc="http://eatfrenzy.com/images/success-tick.png" />
</div>

<div id="thisDoesNotWork">
    this does not work in Chrome. onerror event is not called twice.
    <img src="http://www.asdfjklasdfasdf.com/bogus1.png" 
        onerror="fixit(this);"
        rsrc="http://www.asdfjklasdfasdf.com/bogus2.png|http://eatfrenzy.com/images/success-tick.png" />
</div>

JAVASCRIPT:

function fixit(img)
{
    var arrPhotos = img.getAttribute('rsrc').split('|');

    // change the img src to the next available
    img.setAttribute('src', arrPhotos.shift());

    // now put back the image list (with one less) into the rsrc attr
    img.setAttribute('rsrc', arrPhotos.join('|'));

    return true;    
}

编辑:根据@Sunil D.的评论,Chrome在初始fiddle示例中由于www.asdfjklasdfasdf.com的无效域名未发出新的查询,因此我已经改变了域名以匹配成功的图片,但是文件名不同,所以仍会出现404错误。这证明了无效的域名并非导致Chrome在第二次尝试时退出的原因。

编辑:更新了fiddle并删除了使用jquery来简化操作和排除可能性。

6个回答

6

我尝试了上面提到的方法,使用setAttribute('src', null)会产生副作用,也就是增加另一个请求。

最终,我使用了

    setTimeout(function(){ imgElement.src = 'http://xxxx'; }, 0)

和这个一样!

参见jsfiddle示例。


只需将jsFiddle运行设置为noWrap而不是unload即可。 - AlignedDev

5
好的,明白了。在你为onerror事件分配的函数内部,在将其更改为新值之前,将src属性设置为null
img.setAttribute('src', null);

工作的fiddle

这会导致Chrome重置它,并强制它在后续的src值返回错误时反复调用onerror。

注意:空字符串不起作用,需要使用null
注意2:此修复方法使用纯JavaScript(但不适用于jquery .attr方法)。在我发布了这个解决方案之后,我尝试使用jquery .attr方法将其设置为$img.attr('src', null);,但这种方式不起作用,当我改为JavaScript时,它就可以工作了。我还尝试使用jquery .prop方法,如下所示:$img.prop('src', null);,第一次可以工作,但在几次刷新后失败了。只有纯JavaScript似乎是一个可靠的解决方案。

更新:
好吧,事实证明,尽管上述更改修复了Chrome并导致它像所有其他浏览器(FF、Safari、Opera、IE7-9)一样重复调用onerror事件,但它会导致IE10的onerror事件出现问题,因此在前一行将其设置为=null后,忽略任何分配给src的有效图像。(...叹气)。


你可以一直取悦于某些浏览器,你可以在某些时间内取悦于所有浏览器,但你无法一直取悦于所有浏览器。 - johntrepreneur
1
Jess的答案在所有浏览器中都可靠地工作(尽管他的jsfiddle已经损坏),而且甚至不是一个hack - 你应该接受它,而不是你的答案,因为你的答案会产生额外的请求... - Nikola Bogdanović

0

我尝试了这个方法,在每次 onerror 发生时切换备用资源,如果最终失败,则清除 onerror 以跳出循环。在多个浏览器上的 imgscript 标签上运行良好。

Js:

function alt_(elm, src_list, attr){
  /*elm: element
    src_list: list of links 
    attt: src*/
  if(src_list==[]){
    elm.onerror="";
    return false;
  }
  
  elm[attr]=src_list[0];
  // console.log(src_list[0])
  elm.onerror = function(){alt_(elm, src_list.slice(1), attr)};
}

const alt_logos = ['B1.jpg', 'B2.jpg', 'backupsite.com/B4.jpg']

HTML:

<img src="main.jpg" onerror="alt_(this, alt_logos, 'src')">

适用于Chrome和Firefox。

更新:似乎这对于链接标签(href)不起作用。此外,似乎脚本标记onerror仅触发一次。


0

我认为@Mikhail的想法是正确的,只是原因略有不同。在第二个例子中,您尝试从相同不存在的域名www.asdfjklasdfasdf.com下载2个图像。

当尝试下载bogus1.png时,Chrome无法将域名解析为IP地址。

当尝试从相同不存在的域名下载bogus2.png时,Chrome根本不会做任何事情...因为它知道域名查找失败了。关于Chrome是否应该调度另一个onerror事件的正确行为可能存在争议 :) 我认为它应该这样做。

要证明这一点,只需为bogus2.png的域名添加1个字符即可按预期工作。

编辑

您可以强制它尝试后续下载的一种方法是将<img>src更改为空字符串。这有点hacky,但它有效。您可以将rsrc属性设置为以下内容之一:

rsrc="''|http://www.asdfjklasdfasdf.com/bogus2.png|''|http://eatfrenzy.com/images/success-tick.png"

这样,当出现错误时,您将源设置为''。这似乎也会生成一个错误,然后触发它尝试下一个源...


糟糕!我认为我的编辑有误。您的原始示例现在对我有效,而之前则不行。 - Sunil D.
你的建议很有道理,即在onerror调用之间将“src”属性设置为空字符串。这种方式似乎在Chrome中有效,并且可以不断重复调用它,但不确定原因。 - johntrepreneur
关于域名的观点很有趣,但这不是它崩溃的原因。我已经更改了上面的小提琴,使用相同的域名和虚假的文件名,问题仍然存在。 - johntrepreneur

0

这是正确的行为。您不希望重复下载相同的图像--这是浪费带宽。

Chrome会创建一个内存对象,然后将其应用于所有具有相应src的图像。

如果您需要下载两次,请通过JavaScript创建这些对象,并为每个分配.onload=function() { .. }


它不会下载两次任何内容。在这个示例中,当src属性中的初始图像未找到时,它会触发onerror事件,该事件会将img元素的src属性更改为新的URL。当重新评估并确定新的URL再次是404时,它应该再次调用onerror事件,直到您使用onerror = ''取消引用它。就像其他所有浏览器一样。请在Chrome和其他浏览器中尝试这个示例。 - johntrepreneur

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接