简体   繁体   English

如何在循环中放入async-await? 不工作

[英]How to put async-await in a loop? Not working

I am using ml5 to classify images in a machine learning project. 我使用ml5在机器学习项目中对图像进行分类。 The program takes images path and type from a json file and then it adds each image to the ml5 classifier, which is then used to train machine learning model. 程序从json文件中获取图像路径和类型,然后将每个图像添加到ml5分类器,然后用于训练机器学习模型。

When I try to load only one image into the classifier, it works normally, (however it won't create a model because minimum of 2 are required for it to train). 当我尝试仅将一个图像加载到分类器中时,它可以正常工作(但是它不会创建模型,因为它需要最少2个才能进行训练)。 But when I try to add these images to the classifier in a for loop, it gives me errors. 但是当我尝试将这些图像添加到for循环中的分类器时,它会给我带来错误。

The files are loaded by the load_data() function which is triggered by a button. 这些文件由load_data()函数加载,该函数由按钮触发。 load_data() calls load_imgs(label, nimgs) where label is the folder and nimgs is the number of images in it. load_data()调用load_imgs(label, nimgs) ,其中label是文件夹,nimgs是其中的图像数。 load_imgs(label, nimgs) then loops over nimgs and takes the path of the image specified in data(json file), makes an image element out of it and then adds it to the classifier. 然后load_imgs(label, nimgs)遍历nimgs并获取数据(json文件)中指定的图像的路径,从中生成一个图像元素,然后将其添加到分类器中。

These functions are defined as: 这些功能定义为:

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

    }

Log generated for this code is: 为此代码生成的日志是:

    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)

I expect this to print the actual size of the image in the function callback of classifier.addImage but instead, it is getting a 0x0 texture 我希望这能在classifier.addImage的函数回调中打印图像的实际大小,而是获得0x0纹理

Reading image.height immediately after setting image.src results in getting 0 as height. 设置image.src后立即读取image.height image.src导致0为高度。 After setting src you should wait for the image to load. 设置src您应该等待加载图像。 There's no promise to await for loading the image. 没有承诺await加载图像。 Instead it does have a callback called onload : 相反,它确实有一个名为onload的回调:

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

Try to use the map function instead of for loop, convert nimgs into array and use map function like this: 尝试使用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);

        })
    }))
}

See this explanation: Using async/await with a forEach loop 请参阅以下说明: 使用async / await和forEach循环

See this article fro more infos: https://lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795/ 有关更多信息,请参阅此文章: https//lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795/

What you suggest is a declared bad practice. 你的建议是宣布的不良做法。

Is not a good practice to "put awaits inside loops". “等待内部循环”不是一个好习惯。

Theorics are that you must not to await async operations in every iteration of the loop. 理论上,你不能在循环的每次迭代中等待异步操作。 Instead you must declare all async operations, then await. 相反,您必须声明所有异步操作,然后等待。

This example from ES Lint I think fills your scenario. 我认为ES Lint的这个例子填补了你的场景。

Examples of correct code for this rule: 此规则的正确代码示例:

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

Examples of incorrect code for this rule: 此规则的错误代码示例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM