在迭代之前等待函数完成 运行

Wait for function to finish running before iterating

如何在迭代数组中的下一个值之前等待 image.onload 函数完成 运行?

for (let i = 0; i < Object.keys(images_list_complex_form).length; i++) {
    for (let k = 0; k < images_list_complex_form[i].length; k++) {
        console.log('ITERATE');
        image.onload = function () {
            console.log('STARTED IMAGE ON LOAD');
        }
    }
}

我在接收加载开始的图像之前收到多个 'iterates'

正如@amadan 所建议的,我尝试将 async 和 await 添加到 for 循环中,但是在这样做之后 image111.onload 再也不会被触发。我从来没有看到控制台日志“加载时启动图像”

        async function rectifyMissingSavedImages(images_list_complex_form_array,annotationIndexArray){
            console.log(images_list_complex_form_array);
            for(let i = 0; i < Object.keys(images_list_complex_form_array).length; i++){
                for(const[index2,value2] of Object.entries(images_list_complex_form_array[i])){
                    if (Object.keys(annotationIndexArray).length == 0 || (!annotationIndexArray[i] || annotationIndexArray[i].includes(String(k)) == false)) {
                        let image_url = URL.createObjectURL(value2);
                        let image111 = new Image();
                        let canvas = new fabric.Canvas();
                        
                        console.log(image111);
                        await new Promise((resolve,reject) =>{
                            image111.onload = evt => {
                                console.log("??");
                                console.log('STARTED IMAGE ON LOAD');
                                let background = new fabric.Image(image);
                                canvas.setHeight(background.height);
                                canvas.setWidth(background.width);
                                canvas.setBackgroundImage(background, canvas.renderAll.bind(canvas));
                                console.log("ABOUT TO RESOLVE");

                                image.src = image_url;
                                resolve();
                            }
                        });

这项任务并非完全微不足道。至少如果 src 已经设置 (设置src后会立即加载图片)。

所以如果src已经设置了你需要确定两种情况:

  1. 图像已经加载
  2. 仍在加载中

这可以通过 HTMLImageElement.complete

检查

此外,您需要检查 loaderror 情况,否则您的循环可能会在网络错误或加载图像出现其他问题时卡住。

// create a function to which you can pass the image
// that function will determine if the image was already loaded
// or it has to wait for the image to be loaded
function waitForImage(image) {
  return new Promise((resolve, reject) => {

    // first check if image was already loaded
    if (image.src && image.complete) {
      // check if loading was successful
      // there might be better ways then checking its dimension
      // because this will fail if you load an image that has no size (like tracking pixels)
      if (image.width > 0 || image.height > 0) {
        resolve()
      } else {
        reject()
      }
    } else {
      // resolve in case a successful load
      image.onload = resolve
      // reject in case of an error
      image.onerror = reject
    }
  })
}

async function loadImages() {
  // create some dummy data to make the snipped runable
  let urls = [
    'https://via.placeholder.com/350x150',
    'https://via.placeholder.com/350x150',
    'https://via.placeholder.com/350x150',
    'https://via.placeholder.com/350x150',
    'https://via.placeeeeeeeholder.com/350x150', // intentional typo to make it fail
    'https://via.placeholder.com/350x150'
  ]

  let images = urls.map(url => {
    let image = new Image()
    image.src = url
    return image
  })

  // iterat over the images
  for (let image of images) {
    try {
      // call a function that returns a Promise 
      // and use await wait for the image to load or fail loading
      await waitForImage(image)
      console.log(`loading ${image.src} finished`)
    } catch (err) {
      console.log(`loading ${image.src} failed`)
    }
  }
}

loadImages();

最简单的方法是在循环内创建并等待一个 promise。类似于:

async function loadImages() {
  for (...) {
    await new Promise((resolve, reject) => {
      image.onload = evt => {
        console.log('STARTED IMAGE ON LOAD');
        resolve();
      }
      image.onerror = reject;
    });
  }
}

这是循环可以在 JavaScript 中“暂停”的唯一方法。任何其他方式要么涉及混乱的链接承诺,要么涉及嵌套回调,这更糟糕。