承诺不在 thenable 中提供更新的数组

Promise not giving updated array in thenable

有一个包含一些图片网址的数组。

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

我试图在我的应用程序中加载这些图像一次,然后将它们存储为缓存以备将来使用,这样我就不必一次又一次地加载它们。我正在使用这些图像在 canvas 上绘制它们。我正在执行以下步骤。

  1. 我发起了一个加载所有图片的承诺。 Promise 加载图像并将它们存储到数组中。
  2. 一旦承诺得到解决,我就会在 canvas
  3. 上绘制它们

这是我的代码

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

    })

}

但是当我在 "then" 中安慰 "can_imgs.length" 时,它安慰了零。它应该是长度为 2 的数组。我做错了什么?

问题是您希望 onload 同步调用,但它是异步发生的。因此 can_imgs.push() 很可能发生在您将 can_imgs 传递给 resolve() 之后。

我会尝试以下方法:

let started = 0;
let loaded = 0;

imgs.map((item, i)=>{
   let img1 = new Image()
   img1.src = item.src
   let x = (item.pos * window.innerWidth) / 100

   started++

   img1.onload = (e) => {
      can_imgs.push({img: img1, pos: item.pos})

      loaded++

      if (started === loaded) {
         this.setState({can_imgs: can_imgs}, () => {
            resolve(can_imgs)
         })
      }
   }
})

使用 started === loaded 您正在检查是否所有图像都已加载,然后可以调用 resolve() - 就像在您的原始代码中一样。

希望对您有所帮助!

您的 then 在图像实际加载之前被调用 - 因此在 img.onload 被触发之前。

要解决您的问题,请将每个单独的图像包装在一个承诺中,并在最终解决 loadImage 承诺之前等待所有图像:


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



    })

}