【问题标题】:Wait for image loading to complete in JavaScript在 JavaScript 中等待图像加载完成
【发布时间】:2016-10-17 16:26:58
【问题描述】:

我正在使用 JavaScript 加载图像。像这样的:

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

当我查看日志时,我发现所有图像都加载得很好,因为“加载”变量的值随着每个加载的图像而增加。

但是我想停止任何进一步的操作,直到这个数量达到最大值,所以在设置图像之后,我放置了一个 while 循环。

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

但是我的浏览器只是崩溃了,因为 while 似乎陷入了无限循环。当我检查日志时,我看到“0”被写入了 1000 次,然后是从 1 到 11 的数字(这意味着图像实际上已加载,但 while 并不关心它,并且崩溃得更快比它可能发生的)。

我认为我在这里尝试使用的方法不是解决此问题的正确方法。

在加载网站所需的所有资产之前,我如何才能暂停所有内容?

【问题讨论】:

  • 只要条件为真,就会尽可能快地循环。

标签: javascript html image canvas


【解决方案1】:

使用 Promise 和异步函数,有一个很好的方法可以等待所有图像都加载完毕(没有回调,没有加载的图像计数):

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;
}

或者您可以等待单个图像加载:

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;
}

你可以像这样使用它(使用承诺链):

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

或者在异步函数内部:

const images = await loadImages(myImages);

【讨论】:

  • 终于有人使用 Promise 而不是 jQuery 或计数器,我正在寻找类似的东西!谢谢!
【解决方案2】:

我个人讨厌使用 while()... 我认为最简单的方法是使用事件侦听器。

var img = new Image;
img.addEventListener("load", function () {

//Img loaded

});
img.src= e.target.result;

【讨论】:

  • 非常感谢!我为每个图像添加了一个侦听器,并与他们核对变量是否已达到所需的数量。所以最后开始的事件也会开始脚本的其余部分。只是出于好奇:在图像中添加侦听器的位置是否重要?在定义源之后还是之前?我已经在它之前添加了它,但我想知道它会有什么不同。
  • 我认为我的例子很糟糕。通常,您应该在定位源之前添加事件侦听器。背后的逻辑是在执行者之前有观察者。
【解决方案3】:

Javascript 是单线程的。这意味着如果您添加一个事件侦听器,该侦听器将在当前执行完成之前运行。因此,如果您启动一个依赖事件来结束它的循环,它将永远不会发生,因为该事件永远不会触发,因为当前执行阻止它运行。此外,事件被异步放置在调用堆栈上,因此如果您的执行速度低于事件触发的速度(在调用堆栈上进行调用),您也会面临页面崩溃的风险。当间隔设置为少于代码执行时间时,这是使用 setInterval 时的常见错误。永远不要使用 setInterval。

请记住 Javascript 不能同时做两件事。

处理资源监控加载的最佳方法是使用 setTimeout。

var allLoaded = false;
var imgCount = 0;  // this counts the loaded images
// list of images to load
const imageURLS =["a.jpg","b.jpg","c.jpg","d.jpg","e.jpg"];
// array of images
var images = [];

const onImageLoad = function(){ imgCount += 1; } // onload event
// loads an image an puts it on the image array
const loadImage = function(url){
    images.push(new Image());
    images[images.length-1].src = url
    images[images.length-1].onload = onImageLoad;
}
const waitForLoaded = function(){
    if(imgCount === images.length){
        allLoaded = true;   // flag that the image have loaded
    }else{
        // display  the progress here
        ...

        setTimeout(waitForLoaded,100); // try again in 100ms
    }
}

// create the images and set the URLS
imageURLS.forEach(loadImage);

setTimeout(waitForLoaded,100);  // monitor the image loading

【讨论】:

    猜你喜欢
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 2014-01-02
    • 1970-01-01
    • 2019-09-29
    • 2020-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多