This problem is probably best addressed by "promisifying" the image loading process, ie create a promise that resolves when the images have loaded.
There's a design decision to be made ... whether (a) to swallow load errors or (b) to allow any individual error to cause the whole process to fail.
Assuming (a), you would write something like this :
function loadImages() {
return $.ajax({
url: url,
// other ajax params?
}).then(function(data) {
return $.Deferred(function(dfrd) { // promisify the entire image loading proceess
var imageArray = [];
var counter = 0; // tally of images that have either loaded or failed to load
$(data).find('a').get().map(function(element) {
// map a elements in data to an array of their hrefs
return element.href;
}).filter(function (href) {
// filter out any non-jpe?g|png|GIF
return href.match(/\.(jpe?g|png|GIF)$/);
}).forEach(function(val) {
// for each match, create a Image() object, push onto the array, attach onload and onerror handlers, and set the `src` attribute.
var img = new Image();
imageArray.push(img);
img.onload = function loadHandler() {
counter += 1;
if(counter == images.length) {
dfrd.resolve(imageArray);
}
};
img.onerror = function errorHandler() {
console.log(new Error('image ' + url + val + ' failed to load'));
// Here, you might choose to splice failed Images out of `imageArray`.
counter += 1;
if(counter == images.length) {
dfrd.resolve(imageArray);
}
};
img.src = url + val;
});
});
}).then(function(imageArray) {
changeMargins(imageArray);
return imageArray;
});
}
Notes:
- More typically, one would choose to promisify at the lowest level (ie each Image() individually) but promises are fairly expensive, therefore with 74 images, it's better to promisify en masse.
- By promisifying, and returning a promise from
loadImages()
, its caller is informed of completion of the process - you can chain loadImages().then(...)
and do stuff when the images have loaded/failed.