Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for image loading to complete in JavaScript

I'm loading images with JavaScript. Something like this:

images[0]=new Image();
images[0].onload=function(){loaded++;console.log(loaded)};
images[0].src="assets/img/image.png";

When I look at the log, I see that all the images are loaded nicely, since the value of the "loaded" variable increases with each loaded image.

However I would like to stop any further action to be executed until this amount reaches it's maximum, so right after setting up the images, I place a while cycle.

while(loaded<11){
    document.getElementById("test").innerHTML="Loading "+loaded+"/11";
    console.log(loaded);
}
//Some code here which should only run after everything has been loaded
//In other words: when the statement in the while cycle becomes false

However my browser simply crashes, since the while seems to be stuck in an infinite loop. When I check the log, I see that "0" was written 1000 times, and after that, the numbers from 1 to 11 (which implies that the images in fact gets loaded, but the while does not care about it, and crashes faster than it could happen).

I believe that the method I'm trying to use here is not the right approach to solve this problem.

How can I put everything on hold until every asset which is needed for the site is loaded?

like image 482
Letokteren Avatar asked Dec 01 '22 16:12

Letokteren


1 Answers

Using promises and async functions, there is a nice way to wait until all the images are loaded (no callbacks, no loaded image counting):

async function loadImages(imageUrlArray) {
    const promiseArray = []; // create an array for promises
    const imageArray = []; // array for the images

    for (let imageUrl of imageUrlArray) {

        promiseArray.push(new Promise(resolve => {

            const img = new Image();
            // if you don't need to do anything when the image loads,
            // then you can just write img.onload = resolve;

            img.onload = function() {
                // do stuff with the image if necessary

                // resolve the promise, indicating that the image has been loaded
                resolve();
            };

            img.src = imageUrl;
            imageArray.push(img);
        }));
    }

    await Promise.all(promiseArray); // wait for all the images to be loaded
    console.log("all images loaded");
    return imageArray;
}

Or you can wait for a single image to load:

async function loadImage(imageUrl) {
    let img;
    const imageLoadPromise = new Promise(resolve => {
        img = new Image();
        img.onload = resolve;
        img.src = imageUrl;
    });

    await imageLoadPromise;
    console.log("image loaded");
    return img;
}

You can use it like this (using promise chaining):

loadImages(myImages).then(images => {
    // the loaded images are in the images array
})

Or inside an async function:

const images = await loadImages(myImages);
like image 50
Kimbatt Avatar answered Dec 04 '22 11:12

Kimbatt