JavaScript all images loading before await

Viewed 160

I have a simple JavaScript file that gets multiple image files from a local device and displays a thumb of the images. So far so good.

Once the thumbs are displayed I have a button that calls the addImages() function. I need to display a slide show of the images, one at a time, for 3 seconds. However, what is happening is all the images are showing at the same time, then the sleep function is called, and then remove the image. Here is my code:

        function addImages() {
    var preview = document.querySelector('#display');
                
        async function readAndPreview(file) {
            var reader = new FileReader();
        
                reader.addEventListener("load", async function () {
                    var image = new Image();
                    image.height = 400;
                    image.width = 400;
                    image.title = file.name;
                    image.border = 5;
                    image.src = this.result;
                    preview.appendChild(image);
                    sleep(3000).then(()=> preview.removeChild(image))


                }, false);
        
            reader.readAsDataURL(file);
        }   

    if(files) {
            [].forEach.call(files, readAndPreview);
    }
    }

  function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

It looks like the code iterates through to appendChild and then starts again until all images are added and then calls the sleep functions and then removeChild. Why???

Any help will be appreciated. Thanks.

1 Answers

I have changed a lot of the implementation as proposed by you.

Major changes:-

  1. Having one instance of file reader
  2. Having single image for which we keep on changing the src url after designated time. (Came to this conclusion after I saw that you're trying to append and remove the same image element after certain duration). So yes I am assuming that the focus will always be one image at a time and so the below code.
let files // you must have an array initialized I think
let reader;
const preview = document.querySelector('#display');
let image = new Image();
image.height = 400;
image.width = 400;
image.title = file.name;
image.border = 5;
preview.appendChild(image);

function initReader(){
        reader = new FileReader();
        reader.addEventListener("load", function () {
          image.src = this.result;   
         }, false);   
}

 function addImages() { 
        initReader();        
        async function readAndPreview() {
                for (let index = 0;index<files.length;index++){
                reader.readAsDataURL(files[index]);
                await sleep(3000);
         } 
        }   
        readAndPreview();      
    }

  function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

I haven't run this so there might be scope of mistakes. But this approach should work for your use-case.

Also there is scope of improvement in this approach for smooth transition from one image to another. Usually one can preload all images via blobs URL.createObjectURL and store them in an array over which we loop and update the image src as we did above. Will be much faster since the data is already at client side.

Related