JavaScript Promise 返回数组问题怎么显示undefined呢?

js Promise 返回数组但无法使用

该如何返回结果呢?

let element = document.querySelectorAll('.test')
    let promise = new Promise((resolve,reject) => {
        let imgs = []
            for (var i = 0; i < element.length; i++) {
                html2canvas(element[i],{
                    useCORS: true,
                    allowTaint: false,
                    logging: true
                }).then(function(canvas) {
                    let ctx = canvas.getContext("2d")
                    let page = document.createElement("canvas")
                    page.width = canvas.width
                    page.height = canvas.height
                    page.getContext("2d").putImageData(ctx.getImageData(0, 0, canvas.width, canvas.height), 0, 0)
                    imgs.push(page.toDataURL("image/jpeg", 1.0))
                })
            }
            console.log(imgs,imgs.length)
            resolve(imgs)
        })
    promise.then(e => {
            console.log(e, e.length)
    })

在这里打印e,可以看到是个数组,但e.length显示就是0;而且直接使用e[0]就是undefined

阅读 1.2k
avatarAI BotBETA

你的问题出在异步操作的处理上。html2canvas 函数是异步的,它会返回一个 Promise,这意味着你的 for 循环会立即执行完,然后在下一个事件循环中,所有的 html2canvas Promise 才会被解决。因此,当你在 for 循环结束后调用 resolve(imgs) 时,imgs 数组可能还没有被任何 Promise 填充。

你可以使用 Promise.all 来解决这个问题,它可以使所有的 Promise 都在一个数组中按顺序解决。这是一个修改后的版本:

let element = document.querySelectorAll('.test')
let promises = [];

for (var i = 0; i < element.length; i++) {
  promises.push(html2canvas(element[i], {
    useCORS: true,
    allowTaint: false,
    logging: true
  }));
}

Promise.all(promises).then(imgs => {
  console.log(imgs);
  console.log(imgs.length);
})

在这个版本中,Promise.all(promises) 会等待所有的 html2canvas Promise 都解决,然后返回一个包含所有结果的数组。这个数组会被传递给 .then 方法,因此你可以直接使用 imgs.length 来获取数组的长度,并且 imgs[0] 也不会是 undefined

3 个回答
✓ 已被采纳

resolve(imgs)修改为

if (imgs.length === element.length) {
   resolve(imgs);
 }

并移动到 imgs.push(page.toDataURL("image/jpeg", 1.0)) 后面

因为Promise是异步的,你需要用async/await将其变成同步的

let promise = new Promise(async (resolve,reject) => {
  let imgs = []
  for (var i = 0; i < 10; i++) {
      await new Promise((resolve2,reject2)=>{
        resolve2()
      }).then(()=>{
        imgs.push(i)
      })
  }
  // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 10
  console.log(imgs,imgs.length)
  resolve(imgs)
})
promise.then(e => {
    // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 10
    console.log(e, e.length)
})
let promise2 = new Promise((resolve,reject) => {
  let imgs = []
  for (var i = 0; i < 10; i++) {
      new Promise((resolve2,reject2)=>{
        resolve2()
      }).then(()=>{
        imgs.push(i)
      })
  }
  //[] 0
  console.log(imgs,imgs.length)
  resolve(imgs)
})
promise2.then(e => {
    // 这里是10个10是因为上边循环的i使用var定义的,改用let即可,不过对你原代码无所谓
    // [10,10,10,10,10,10,10,10,10,10] 10
    console.log(e, e.length)
})

Promise的传入的函数是同步执行的,你这里 resolve 放在同步阶段去触发了,拿到的 imgs 肯定还是空的,then部分注册的回调是异步流程,执行时序肯定在 resolve 之后
image.png

你这里 resolve 需要放到 then 成功的回调里面去触发,也就是楼上的解决方案

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Microsoft
子站问答
访问
宣传栏