user3282203 user3282203 - 1 month ago 16
Javascript Question

JQuery delayed + queued calls

I have a page in which a stream of events with images is displayed in real-time. Since it's in real-time (as the event occurs), it's possible the image isn't quite available yet as it's still being uploaded to storage.

Calls to get new events are executed every couple of seconds, and each call can return up to 20 events (the latest 20), but usually it's between 0 and 5.

Due to the issue of images potentially not loading initially, an

onerror
function is used:

<img onerror="retryImage(this, 'imageUrl', 0)" src="imageUrl" />

function retryImage(source, url, attempts) {
img = new Image();
img.src = url + '?' + (new Date()).getTime();
img.onload = function() {
source.src = img.src;
};
img.onerror = function() {
if (attempts > 4) {
source.src = 'not_found.png';
} else {
source.src = 'loading.gif';
attempts++;
$(this).delay(2000).queue(function() {
retryImage(source, url, attempts);
$(this).dequeue();
});
}
};
return true;
}


The idea is to attempt to load the image, and if it fails, wait a couple of seconds and try again, up to 5 times.

Unfortunately, in practice every now and then (when a number of images fail to load initially, at the same time), one of the images displayed will belong to a different event. Which leads me to think I'm misusing the
delay()
and
queue()
functions?

Any thoughts?

Answer

You are indeed; delay and queue are intended for use specifically with jQuery effects. Quoting from the documentation:

The .delay() method is best for delaying between queued jQuery effects. Because it is limited—it doesn't, for example, offer a way to cancel the delay—.delay() is not a replacement for JavaScript's native setTimeout function, which may be more appropriate for certain use cases.

I believe this is precisely such a use case! Try something like:

function retryImage(source, url, attempts) {
  img = new Image();
  img.src = url + '?' + (new Date()).getTime();
  img.onload = function () {
    source.src = img.src;
  };
  img.onerror = function () {
    if (attempts > 4) {
      source.src = 'not_found.png';
    } else {
      source.src = 'loading.gif';
      attempts++;
      setTimeout(function () {
        retryImage(source, url, attempts);
      }, 2000);
    }
  };
  return true;
}
Comments