6

A webpage contains few images, 5-10, average size.

Sometimes, randomly, the loading of an image fails and it is not displayed.

Let say that every 100 images loaded 1 fails.

That may happen because the server is busy or there is a temporary network problem, any reason..

I know for sure that the request to obtain the image is valid so if I retry to load the image I have very good chances to get it.

I have code to detect when an image fails to load and trigger a callback.

But then, how can I tell the browser "retry loading that image" ?

Can I just remove the image from the DOM and put it back again?

If I append to the URL a random query string the image will be reloaded for sure but I'd prefer to avoid that because the image won't be properly cached.

I'm using jQuery, so a jQuery solution is good for me as pure JavaScript.

Muhd
  • 24,305
  • 22
  • 61
  • 78
Paolo
  • 15,233
  • 27
  • 70
  • 91
  • maybe trying something like this might help: http://stackoverflow.com/questions/2104949/how-to-reload-refresh-an-elementimage-in-jquery – Software Guy Apr 18 '14 at 18:39
  • 1
    No need for callbacks. Use `onerror` handling. See this as an example: http://stackoverflow.com/questions/92720/jquery-javascript-to-replace-broken-images – Yuriy Galanter Apr 18 '14 at 18:40
  • 1
    @YuriyGalanter I assumed he meant he was attaching a callback to the onerror event. – Muhd Apr 18 '14 at 18:41
  • I believe [this][1] may be the answer you're looking for. [1]: http://stackoverflow.com/questions/1077041/refresh-image-with-a-new-one-at-the-same-url/9943419#9943419 – Richard Apr 18 '14 at 18:43

2 Answers2

15

What you can do is just try to load the image in a new Image object. If an image loads, it will update all other places as well (similar to how if you embed the same image 50 times, once it loads once, they all show). So, in your callback (which I assume is an error callback), just try:

var img = new Image();
img.src = this.src; // this should refer to the original failed image

That'll trigger the loading of that same URL in the new image object. If it works, both will be updated and the one we just created is simply never shown anywhere.

samanime
  • 25,408
  • 15
  • 90
  • 139
  • I haven't tested it, but it should work pretty far back in all browsers. The only catch may be for really old ones, `this.src` might not work and you need to use `this.getAttribute('src')` instead. – samanime Apr 18 '14 at 18:45
  • I will try that and let you know. Thank you – Paolo Apr 18 '14 at 20:22
  • Looks like this doesn't work anymore (Chrome 98). Even if I add the new image to the DOM (and it loads correctly), the original doesn't update. – Sphinxxx Feb 11 '22 at 14:59
  • Interesting. I don't have an environment handy that I can test this in, but if this doesn't work anymore, you can probably find all images on the page with `document.querySelectorAll('[src*=""]')`, then go through each and append something that won't affect them but will force a reload (like `?${Date.now()}`) to force them to update. Surprised they changed this behavior though. Perhaps the behavior was always just a side-effect and not intentional. – samanime Feb 11 '22 at 15:08
3

Inspired by samanime's suggestion, I came up with below lines of code. I call this code in jquery's document-ready event. See if it helps someone, also let me know if it requires improvements,

if (document.images) {
    var imageArray = new Array(document.images.length);
    var i = 0;
    for (i = 0; i < document.images.length; i++) {
        $(document.images[i]).attr('dt-retry', 3);
        imageArray[i] = new Image();
        imageArray[i].src = document.images[i].src;
        //try to reload image in case of error
        //retry for 3 times
        var imgErrorFunction = function () {
            try {
                var img = this;
                var isRet = true;
                var r = 3;
                if (img.hasAttribute('dt-retry')) {
                    r = parseInt(img.getAttribute('dt-retry'));
                    r = r - 1;
                    img.setAttribute('dt-retry', r);
                    if (r <= 0) {
                        isRet = false;
                    }
                }

                if (isRet) {
                    var temp = new Image();
                    temp.setAttribute('dt-retry', r);
                    temp.onerror = imgErrorFunction;
                    temp.src = img.src;
                }
            } catch (e) {

            }
        }

        document.images[i].onerror = imgErrorFunction;
    }
}
Falko
  • 17,076
  • 13
  • 60
  • 105
pgcan
  • 1,199
  • 14
  • 24
  • as you asked... it could be improved with a mechanism to handle situations where new images are loaded dynamically. I'm thinking about web pages with lazy loading images dor example (this is my case by the way) – Paolo Dec 08 '16 at 17:05