如何将异步等待放入循环中?不起作用。

4

我在一个机器学习项目中使用ml5来对图像进行分类。程序从json文件中获取图像路径和类型,然后将每个图像添加到ml5分类器中,最终用于训练机器学习模型。

当我尝试将单个图像加载到分类器中时,它可以正常工作(但由于需要至少2张图片,因此不会创建模型以进行训练)。但是当我尝试在for循环中将这些图像添加到分类器中时,它会给出错误信息。

这些文件是由load_data()函数加载的,该函数由一个按钮触发。 load_data()调用load_imgs(label, nimgs),其中label是文件夹,nimgs是其中包含的图像数量。 load_imgs(label, nimgs) 然后循环遍历nimgs,并获取数据(json文件)中指定的图像路径,将其制作成图像元素,然后添加到分类器中。

这些函数定义为:

    async function load_imgs(label, nimgs) {

        const forLoop = async _ => {
            for (let i = 0; i < nimgs; i++) {
                const imageData = await data.children[label].children[i]
                const image = document.createElement("img")
                image.src = imageData.path
                const type = await imageData.type;
                await classifier.addImage(image, type, (res) => {
                    console.log("image added to classifier", image.height);
                    console.log(image);

                })

            }
        }
        await forLoop()
    }

    function load_data() {
        (async() => {
            try {
                await load_imgs(0, googleImages);
                await load_imgs(1, amazonImages);
                await load_imgs(2, paypalImages);
                await load_imgs(3, facebookImages);
                await load_imgs(4, dropboxImages);
                console.log("images added");

            } catch (error) {
                console.log(error);
            }
        })();

    }

这段代码生成的日志如下:

    index-train.html:106 Live reload enabled.
    train.js:84 json loaded
    train.js:69 Model loaded
    train.js:38 image added to classifier 0
    train.js:39 <img src=​"all_data/​google/​google_85.png">​
    train.js:107 Error: Requested texture size [0x0] is invalid.
        at re (tf-core.esm.js:17)
        at Wi (tf-core.esm.js:17)
        at Gi (tf-core.esm.js:17)
        at t.createUnsignedBytesMatrixTexture (tf-core.esm.js:17)
        at t.acquireTexture (tf-core.esm.js:17)
        at t.acquireTexture (tf-core.esm.js:17)
        at t.uploadToGPU (tf-core.esm.js:17)
        at t.getTexture (tf-core.esm.js:17)
        at t.fromPixels (tf-core.esm.js:17)
        at t.fromPixels (tf-core.esm.js:17)

我希望在classifier.addImage函数的回调中打印出图像的实际尺寸,但实际上它得到的是一个0x0的纹理。


await data.children[label].children[i] 这是什么? - zerkms
数据是一个JSON,它被加载到一个对象中。label表示文件夹的索引,它在JSON中定义了顺序。i代表包含图像文件本地路径的字符串。 - Akhilesh Sharma
添加 image.onload 监听器。image.src = imageData.path 并不意味着你的图像已经加载完成。 - lx1412
这个问题可能会有所帮助:这个问题 - A. M.
@lx1412 感谢大家,这就像我的手指上的刺一样。非常感谢你们。 - Akhilesh Sharma
3个回答

2
你提出的建议是一种被宣布为不良实践的做法。
在循环内部使用"await"并不是一个好的实践。
理论上,你不应该在每次循环迭代中等待异步操作完成。相反,你应该先声明所有的异步操作,然后再等待它们完成。
我认为ES Lint的这个例子符合你的场景。
以下是符合此规则的正确代码示例:
async function foo(things) {
  const results = [];
  for (const thing of things) {
    // Good: all asynchronous operations are immediately started.
    results.push(bar(thing));
  }
  // Now that all the asynchronous operations are running, here we wait until they all complete.
  return baz(await Promise.all(results));
}

这个规则的错误代码示例:
async function foo(things) {
  const results = [];
  for (const thing of things) {
    // Bad: each loop iteration is delayed until the entire asynchronous operation completes
    results.push(await bar(thing));
  }
  return baz(results);
}

1

在设置image.src后立即读取image.height会得到高度为0的结果。在设置src后,您应该等待图像加载完成。没有承诺来等待图像加载,但确实有一个名为onload的回调函数。

let img = new Image();
img.onload = function() { console.log("Height: " + this.height); }
img.src = "...";

1

尝试使用map函数代替for循环,将nimgs转换为数组并像这样使用map函数:

async function load_imgs(label, nimgs) {

    await Promise.all(nimgs.map(async (i) => {
        const imageData = await data.children[label].children[i]
        const image = document.createElement("img")
        image.src = imageData.path
        const type = await imageData.type;
        await classifier.addImage(image, type, (res) => {
                console.log("image added to classifier", image.height);
                console.log(image);

        })
    }))
}

查看此解释:如何在forEach循环中使用async/await

查看此文章获取更多信息:https://lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795/


image.onload 已经解决了问题,不过还是谢谢,我也会尝试这个方法。 - Akhilesh Sharma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接