Search code examples
javascriptpromisees6-promise

Promise not giving updated array in thenable


There is an array which contains some image urls.

const imgs = [{
    src:'./canvas-img1.jpg',
    pos: 20
}, {
    src: './canvas-img2.jpeg',
    pos: 25
}]

I am trying to laod these images once in my application and then store them as cache for future use so that i don't have to load them again and again. I am using these images to draw them on canvas. I am doing the following steps.

  1. I initiate a Promise to load all the images. Promise loads the images and stores them into an array.
  2. Once the promise is resolved, I draw them on canvas

Here is my code

drawCanvas(){
    let canvas = document.getElementById("timeline-canvas")
    let canvas_container = document.getElementById("canvas-container")
    let ctx = canvas.getContext("2d")


    this.loadImage().then((can_imgs)=>{
        console.log(can_imgs.length) // this is coming as array of length 0
        this.state.can_imgs.map((item, i)=>{
            let x = (item.pos * window.innerWidth)/100
            ctx.drawImage(item.img, x,0, 100, 100);
        })
    })
    ctx.save()
}

//load images only once and cache them
loadImage = () => {
    return new Promise(resolve => {
        imgs.map((item, i)=>{
            let img1 = new Image()
            img1.src = item.src
            let x = (item.pos * window.innerWidth)/100
            img1.onload = function (e)
            {
                can_imgs.push({img: img1, pos: item.pos})
            }
        })
        this.setState({can_imgs: can_imgs}, ()=>{
             resolve(can_imgs)
        })

    })

}

But when I console "can_imgs.length" in "then", it consoles zero. It should be array of length 2. What am I doing wrong?


Solution

  • Your then is called before the images are actually loaded - so before img.onload is triggered.

    To solve your problem, wrap each individual image in a promise and await all of them before finally resolving the loadImage promise:

    
    loadImage = () => {
        return new Promise(resolve => {
    
            let images = imgs.map((item, i)=> new Promise((resolve) => {
                let img1 = new Image()
                img1.src = item.src
                let x = (item.pos * window.innerWidth)/100
                img1.onload = function (e)
                {
                    can_imgs.push({img: img1, pos: item.pos})
                    resolve()
                }
            }))
    
            // wait for all images to resolve
            Promise.all(images).then(() => {
                this.setState({can_imgs: can_imgs}, ()=>{
                    resolve(can_imgs)
                })
            })
    
    
    
        })
    
    }