One way is to return a Promise
for each image that you load. This promise will resolve, or in laymen terms: continue when the right condition is met, whenever the images has been loaded. It's like a return
statement but instead of ending the function you continue to the next step.
Promise.all
is a method on the promise constructor which takes in an array of promises. When all of the promises in the array have been fullfilled (meaning resolve
has been called) then do something with the values of all of the promises.
const loadImage = (source) => new Promise(resolve => {
let img = new Image();
img.onload = function() {
resolve(img);
};
img.src = source;
});
const whenAllImagesAreLoaded = (...sources) => Promise.all(
sources.map(source => loadImage(source));
);
whenAllImagesAreLoaded('image-1.jpg', 'image-2.jpg').then((images) => {
images.forEach(image => {
console.log(image, ' is loaded');
});
});
Another example is also with promises in combination with the async
/ await
syntax, which halt execution until the promise you are waiting for has been fulfilled.
This opens up the possibility to, for example: load images one after another, after the previous image has been loaded.
async function loadImagesSequentially(...sources) {
for (const source of sources) {
let image = await loadImage(source);
console.log(image, ' is loaded');
}
}
Both methods give you better control over how to handle race conditions, or eliminate them completely. I'd suggest that you practice as much as you can with promises. It is a very powerful tool in your JavaScript toolbox.
If you have any questions, please let me know.