'Why is Chrome's onerror event for the img element only fired once?

Why is Chrome is only calling the onerror event for the img element one time when all other browsers (IE7,8,9, FF, Opera, and Safari) all call it repeatedly?

Is there a way to force it to repeat the onerror call again (in Chrome)?

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;    
}

EDIT: Per @Sunil D.'s comment about Chrome not issuing a new lookup due to invalid domain name of www.asdfjklasdfasdf.com in the initial fiddle example, I went ahead and changed the domain name to match that of the success image, but with a different filename so it still is a 404. That will prove it's not the invalid domain name causing Chrome to bail out on the 2nd attempt.

EDIT: Updated fiddle and removed use of jquery to simply things and rule that out.



Solution 1:[1]

Okay got it. Inside the function you assign to the onerror event, set the src attribute to null before changing it to it's new value.

img.setAttribute('src', null);

working fiddle

This somehow causes Chrome to reset it and will force it to repeatedly call onerror if subsequent values for src return an error.

Note: an empty string won't work and needs to be null.
Note2: this fix works using pure javascript (but not with the jquery .attr method). After I posted this solution I tried it with the jquery .attr method setting it to $img.attr('src', null); but it didn't work that way and when I changed it to javascript, it worked. I also tried it using the jquery .prop method instead like so $img.prop('src', null); which worked the first time and failed on a few subsequent refreshes. Only the pure javascript seems to be a surefire solution.

UPDATE:
Okay, turns out that while the above change fixes Chrome and causes it to repeatedly call onerror like all other other browsers (FF, Safari, Opera, IE7-9), it causes problems with the onerror event for IE10 and thus ignores any valid images assigned to src after setting it to =null on the previous line. (...sigh).

Solution 2:[2]

I've tried the ways metioned above, setAttribute('src', null) has a side effect, ie, add another request.

Finally, I use

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

, and this works!

See the jsfiddle for example.

Solution 3:[3]

This is the correct behavior. You don't want to download the same image twice -- that's a waste of bandwidth.

What Chrome does it create an in-memory object and then will apply it to all images with the respective src.

If you need it downloaded twice, then create those objects through javascript and assign .onload=function() { .. } to each.

Solution 4:[4]

I think @Mikhail is on the right track, except for a slightly different reason. In the second example, you attempt to download 2 images from the same non-existent domain www.asdfjklasdfasdf.com.

When attempting to download bogus1.png, Chrome fails to resolve the domain to an IP address.

When attempting to download bogus2.png (from the same non-existent domain), Chrome doesn't do anything at all... because it knows the domain lookup has failed. Whether it's correct behavior for chrome not to dispatch another onerror event might be open to debate :) I sort of expect that it should.

To prove this, simply add 1 character to the domain name for bogus2.png and it will work as you expected.

Edit

One way you could force it to attempt the subsequent downloads is to change the src of the <img> to the empty string. It's kind of hacky, but it works. You could set your rsrc attribute to something like this:

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

This way, when the error occurs, you set the source to ''. This seems to generate an error too, which then triggers it to try the next source...

Solution 5:[5]

As answered by Etdashou on this question : https://stackoverflow.com/a/9891041/1090274, setting this.onerror=null; worked for me.

Solution 6:[6]

I tried this, keep switching alternate sources on each onerror, and if finally fails, clears the onerror to break to the loop. Works fine on img, script tags on multiple browses.

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')">

Works both chrome and FF.

Update: seems this won't work for link tags (href). Also, seems like script tag onerror fires only once.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Jess
Solution 3 Mikhail
Solution 4 Sunil D.
Solution 5 Community
Solution 6