检查页面中的所有图像是否已加载完成

4

目标:检查页面中的所有图片是否已经加载。如果是,则调用一个函数;如果没有加载完成,则再次检查是否所有图片都已加载。

我的尝试

let checkImages = new Promise(resolve => { resolve(areCompleted()); });

function areCompleted() {
  let images = document.querySelectorAll('img');
  images = Array.from(images);

  for (let i = 0; i < images.length; i++) {
    if (!images[i].complete) {
      return false;
    }
  }
  return true;
}

如果所有图片都完成了加载,它会返回 true,否则返回 false。
checkImages.then(completed => {
  if (completed) {
    completedFunction();
  } else {
    // Check again
  }
});

如果响应为真,则调用函数,如果不是...我不知道如何再次进行相同的检查,但我希望一直进行该检查,直到响应为真。

1
这似乎是 Promise 的一个奇怪用法。通常只有当所有图片都加载完成后才会 resolve。 - Quentin
你只是想在所有图像加载完成后触发事件,还是必须使用Promise? - Reinstate Monica Cellio
@Archer 如果我想要进行这个检查,我只能考虑使用 async。我已经尝试过使用 while,但在3G网络中它会阻塞脚本。在 async 中,我只知道两种方法:Promiseasync/await 函数。 - Angel Luis
1
当图像加载完成时,它们会触发一个事件。你不需要一遍又一遍地检查它们。我会为你编写一些代码。 - Reinstate Monica Cellio
1
承诺不是一个函数,你不能调用它。 - Bergi
显示剩余4条评论
2个回答

12

这个函数将检查已经加载的图像,并为所有其他图像附加事件侦听器,以便它可以在给定容器中的每个图像加载完成时通知...

function onImagesLoaded(container, event) {
    var images = container.getElementsByTagName("img");
    var loaded = images.length;
    for (var i = 0; i < images.length; i++) {
        if (images[i].complete) {
            loaded--;
        }
        else {
            images[i].addEventListener("load", function() {
                loaded--;
                if (loaded == 0) {
                    event();
                }
            });
        }
        if (loaded == 0) {
            event();
        }
    }
}

var container = document.getElementById("container");

onImagesLoaded(container, function() {
    alert("All the images have loaded");
});
<div id="container">
  <img src="https://cdn.vox-cdn.com/thumbor/C1SdoDActSv8tPONx_OjwEobUjw=/0x0:1004x753/1200x800/filters:focal(0x0:1004x753)/cdn.vox-cdn.com/uploads/chorus_image/image/49523369/20150428-cloud-computing.0.jpg" />
  <img src="https://images.techhive.com/images/article/2016/08/clouds-100678070-primary.idge.jpg" />
  <img src="https://www.quali.com/wp-content/uploads/2016/04/101-HEADER-IMAGE.jpg" />
  <img src="https://cdn.computerworlduk.com/cmsdata/features/3641280/cloud_istock_malerapaso_thumb800.jpg" />
</div>

如果所有图片都已经被缓存或者容器内没有图片,这个方法仍然可以使用。

如果你想检查页面中的所有图片,只需将容器选择器改为body即可...

var container = document.getElementsByTagName("body")[0];

这是一个有效的解决方案,但是,如果在JS引擎添加事件监听器时图像被加载会发生什么?(在那个精确的毫秒内) - Angel Luis
这是不可能的 - 其中一个必须先发生。 - Reinstate Monica Cellio
但是图片下载不是由浏览器异步执行的吗? - Angel Luis
1
这种情况发生的可能性非常小,但如果在添加事件处理程序时恰好加载图像,则下一件事将是JS被通知图像已加载。虽然图像加载是异步的,但JS不是。图像状态在该代码期间无法更改。只能在之前或之后更改。 - Reinstate Monica Cellio
这是一个可靠的解决方案,但在循环中引用外部作用域变量可能会令人困惑。有什么方法可以避免这种情况? - bytrangle
如果图像的src无效,我认为这将失败,事件监听器应该同时监听error事件和load事件。 - Koen

0
被接受答案中的代码非常巧妙,只有一个小问题需要补充 —— 如果页面上没有任何图片,事件不会被调用,因为检查是否为0的条件在循环内部。所以我建议做出这个小改变:
function onImagesLoaded(container, event) {
    var images = container.getElementsByTagName("img");
    var loaded = images.length;
    for (var i = 0; i < images.length; i++) {
        if (images[i].complete) {
            loaded--;
        }
        else {
            images[i].addEventListener("load", function() {
                loaded--;
                if (loaded <= 0) {
                    event();
                }
            });
        }
    }
    if (loaded <= 0) {
        event();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接