美文网首页
forEach 循环和promise同时使用 await会失效

forEach 循环和promise同时使用 await会失效

作者: litielongxx | 来源:发表于2023-08-31 10:52 被阅读0次

forEach 循环可以与 Promise 一起使用,但是会导致 await 失效,得用for of替代。
场景复现:
uniapp u-upload图片上传h5网页 ,uview不支持网页压缩加了个方法
后来才发现循环中,上传方法时一直没等压缩完就先跑了,导致一直上传空路径,自然返回也为空。
原理
forEach 是一个用于遍历数组的方法,它会对数组中的每个元素都执行一个提供的回调函数。然而,forEach 并不会等待每个回调函数的异步操作完成,它会继续执行下一个循环迭代,这可能会导致问题。如果在 forEach 循环中使用 await,由于 forEach 本身不会等待异步操作完成,await 可能无法按预期工作。

示例代码:

items.forEach(async item => {
    // Some asynchronous operation
    await doSomethingAsync(item);
    console.log(`Processed ${item}`);
});
console.log("Loop finished");

在上面的代码中,doSomethingAsync 是一个异步操作,但是由于 forEach 不会等待每个回调函数内部的异步操作完成,"Loop finished" 可能会在异步操作完成之前就被打印出来。

为了解决这个问题,您可以使用 for...of 循环与 await 结合,或者使用 Promise.all 来等待所有异步操作完成:

使用 for...of 循环:

for (const item of items) {
    await doSomethingAsync(item);
    console.log(`Processed ${item}`);
}
console.log("Loop finished");

使用 Promise.all:

const items = [1, 2, 3, 4];

await Promise.all(items.map(async item => {
    await doSomethingAsync(item);
    console.log(`Processed ${item}`);
}));

console.log("Loop finished");

这两种方法都会确保在异步操作完成后再进行下一次迭代,以保持 await 的正常工作。
额外:
uniapp压缩网页图片代码

methods:{
base64实际为图片url地址
dealImage(base64) {
      return new Promise(resolve => {
        var newImage = new Image()
        var quality = 0.7 //压缩系数0-1之间
        if (base64.length / 1024 > 1024 * 2) {
          quality = 0.5
        }
        if (base64.length / 1024 > 1024 * 5) {
          quality = 0.3
        }
        newImage.src = base64
        newImage.setAttribute('crossOrigin', 'Anonymous') //url为外域时需要
        var imgWidth, imgHeight
        let self = this
        newImage.onload = function() {
          imgWidth = this.width
          imgHeight = this.height
          var canvas = document.createElement('canvas')
          var ctx = canvas.getContext('2d')
          canvas.width = imgWidth / 2
          canvas.height = imgHeight / 2
          ctx.clearRect(0, 0, canvas.width, canvas.height)
          ctx.drawImage(this, 0, 0, imgWidth / 2, imgHeight / 2)
          var base64 = canvas.toDataURL('image/jpeg', quality) //压缩语句
          // base64转为url
          let file = self.convertBase64UrlToFile(base64)
          resolve(file.path)
        }
      })
    },
convertBase64UrlToFile(base64) {
      let urlData = base64
      let type = base64.type
      let contentName = new Date().getTime()
      let bytes = null
      if (urlData.split(',').length > 1) {
        //是否带前缀
        bytes = window.atob(urlData.split(',')[1]) // 去掉url的头,并转换为byte
      } else {
        bytes = window.atob(urlData)
      }
      // 处理异常,将ascii码小于0的转换为大于0
      let ab = new ArrayBuffer(bytes.length)
      let ia = new Uint8Array(ab)
      for (let i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i)
      }
      let result = new Blob([ab], {
        type: type
      })
      let result1 = new File([result], contentName, {
        type: type
      })
      result1.path = window.URL.createObjectURL(result)
      return result1
    },
//  使用方式用到了promise 等待压缩完成和await 配套(async/await成套存在,相当于标识符/语法糖,相当于规定了+时两边相加,这里相当于看到就知道是promise 可以等待执行)

    async xx() {
    const newUrl =  await this.dealImage(item.url)
  }
}

相关文章

网友评论

      本文标题:forEach 循环和promise同时使用 await会失效

      本文链接:https://www.haomeiwen.com/subject/tshzmdtx.html