How do I make sure that all the N images on the page have been loaded and the size of the page has been determined?

We made a Web App, in which the DOM structure is obtained from the background (wrapped in a section element), and then append to a container div. After
, you need to calculate the size information of the newly added section.
We found that once the section contains some img elements, it will cause append to calculate the size immediately, and the data obtained is inaccurate.
We have used Mutation Observer to monitor element changes under container, delaying computing time. But this method can not solve the problem of pictures.

how can we seize the time when all the pictures have been loaded and the layout of the page will not be affected after that?

Thank you all.

Jun.02,2021

effect

clipboard.png

Code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>

<body style="background:-sharpeee">
    <script>
     const images = [
        "https://avatar-static.segmentfault.com/102/500/1025005915-54cb538538eea_small",
        "https://static.segmentfault.com/v-5b8f9b7e/global/img/user-64.png",
     ];
     Promise.all(
        images.map(url=>new Promise((resolve,reject)=>{
            const img = new Image();
            img.addEventListener("load",function(){
                // 
                this.__isOK__ = true;
                resolve(this);
            },{once:true})
            img.addEventListener("error",function(){
                this.__isOK__ = false;
                resolve(this);
            },{once:true});
            
            img.src = url;
        }))
     ).then(arr=>{
        const success = arr.filter(img=>img.__isOK__);
        console.log(`${arr.length}${success.length}`)
        console.log(`:\n${success.map(img=>`${img.naturalWidth}${img.naturalHeight}`).join("\n")}`);
     })
    </script>
</body>
</html>

the img tag already exists, so you can get the number of tags. You can add onload/error callback to img , and then count in the callback to know whether the picture has been successful or failed.


well, there is a small problem. What is the purpose of determining this size


this is the preloading process,

var imgLoad = function (url, callback) {
        var img = new Image();
         img.src = url; 
       if (img.complete) {
          callback(img.width, img.height);
       }  else {
         img.onload = function () { 
             callback(img.width, img.height);
             img.onload = null; 
          }
        }


if you want to determine that all pictures have been loaded, there are two ways:

  1. listen for load events (or onload='' )
  2. for all pictures.
  3. traverse the pictures regularly, checking their naturalWidth properties

first all the pictures in the dom structure returned by Filter.
then traverses to listen for onload events of the picture.
then count, if the number of counts in the current onload time that triggers the callback is equal to the length of the img array, trigger callback (calculate the width and height of the outer container.)


it is recommended that after getting the data, preload all the images first, and then append them to dom.
there are many preloading implementations depending on the running environment. Here is a simple illustration (using promsie):

)
function _loadImage(item) {
  return new Promise((resolve, reject) => {
    var image = new Image();
    image.onload = () => {
      resolve();
    };
    image.onerror = err => {
      resolve();
    };
    image.src = item.src;
  });
}
function loadeImages(imgs) {
  const tasks = imgs.map(img => _loadImage(img));
  return Promise.all(tasks);
}
loadeImages(imgList).then(() => {
    // append to div
})
Menu