如何等待来自 for 循环的多个异步调用?

Posted

技术标签:

【中文标题】如何等待来自 for 循环的多个异步调用?【英文标题】:How to wait for multiple asynchronous calls from for loop? 【发布时间】:2019-02-15 23:59:35 【问题描述】:

没有任何处理的代码:

  for (i=0; i<dbImgCount; i++)
        (function(i) 
             imgDownload(FolderPath[i].FolderPath, function (next)
                var url = FolderPath[i].FolderPath;
                const img2 = cv.imread(imgDownload.Filename);
                match(url,
                    img1,
                    img2,
                    detector: new cv.ORBDetector(),
                    matchFunc: cv.matchBruteForceHamming,
                );

            )
        )(i);
      

在上面的代码中,imgDownload 是一个用于下载图像的async function,match 会将下载图像的特征与另一个图像匹配。在for-loop之后需要执行一个函数。

如何重构这段代码,使用Promiseasync-await,使得每次调用异步函数都被等待并且只有在完成for-loop之后,流程才能继续?


async-await编辑代码:

    FolderPath.forEach(FolderPath => 
        (async function () 
            var filename = await imgDownload(FolderPath.FolderPath);
            var url = FolderPath.FolderPath;
            const img2 = cv.imread(filename);
            imgs = await match(url,
                img1,
                img2,
                detector: new cv.ORBDetector(),
                matchFunc: cv.matchBruteForceHamming,
            );
        )();
    );

    function someFunction()
       console.log("After forEach");
    

someFunctiononly如何在forEach之后执行?

【问题讨论】:

imgDownload 支持承诺吗?如果没有,start with that "这样我就可以在此之后执行回调函数。" - 不,如果你想使用 Promise,你不会在之后调用回调函数这样,您将改为返回匹配的承诺。 我使用了 image-downloader npm 包,它支持 Promise。 npmjs.com/package/image-downloader 好的。您是否查看了their example 并尝试将其应用于您的案例? 使用异步/等待?我该怎么办? var promise1 = new Promise(function(resolve, reject) resolve('Success!'); ); promise1.then(function(value) console.log(value); // 预期输出:“成功!” );这样使用promise? 【参考方案1】:

在您上次更新时,虽然您在 for-loop 中使用了 async-await,但这并没有阻止您的同步流程。

我假设您的 imgDownloadmatch 函数正在返回承诺。

那么新代码将是:

(async function () 

    // Next loop won't be executing without completing last.
    for (i = 0; i < FolderPath.length; i++) 

        var filename = await imgDownload(FolderPath[i].FolderPath);
        var url = FolderPath[i].FolderPath;

        const img2 = cv.imread(filename);

        imgs = await match(url,
            img1,
            img2,
            detector: new cv.ORBDetector(),
            matchFunc: cv.matchBruteForceHamming,
        );
    

    // Now will wait for for-loop to end
    function someFunction()
       console.log("After forEach");
    
// End of async-await
)();

这是一个小示例:

(async function ()  
    for (i=0; i<5; i++) 
        x = await main();
        console.log(x, i);
    
    console.log("Finally");
)();

// asynchronous main function
function main() 
    return new Promise( (resolve, reject) => 
        setTimeout(()=>  resolve('Done'); , 5000)
    );

【讨论】:

SyntaxError: await is only valid in async function 这将是输出。 awaitasync 函数内【参考方案2】:

感谢大家的cmets。

   (async function ()  
        for (i = 0; i < FolderPath.length; i++) 
            var filename = await imgDownload(FolderPath[i].FolderPath);
            var url = FolderPath[i].FolderPath;
            const img2 = cv.imread(filename);
            imgs = await match(url,
                img1,
                img2,
                detector: new cv.ORBDetector(),
                matchFunc: cv.matchBruteForceHamming,
            );
        
        console.log("After forEach");
    )();

这是工作 - "After forEach" 仅在 for 循环后显示。


当使用上面答案中提到的forEach 时。

(async function () 

   // Next loop won't be executing without completing last.
  FolderPath.forEach(FolderPath => 

    var filename = await imgDownload(FolderPath.FolderPath);
    var url = FolderPath.FolderPath;

    const img2 = cv.imread(filename);

    imgs = await match(url,
        img1,
        img2,
        detector: new cv.ORBDetector(),
        matchFunc: cv.matchBruteForceHamming,
    );
);

// Now will wait for for-loop to end
function someFunction()
   console.log("After forEach");

// End of async-await
)();

输出是 - SyntaxError: await is only valid in async function

我认为await关键字不会在async函数的范围内,当它在forEach下时,应该是这个原因。

【讨论】:

是的,没注意到,forEach 带有一个callback 函数,这使它超出了async 的范围,因此awaitasync 之外使用。 您可以使用for-loop 编辑我的答案,因为它可以解决您的问题。

以上是关于如何等待来自 for 循环的多个异步调用?的主要内容,如果未能解决你的问题,请参考以下文章

Node.js/Mongoose 等待异步 For 循环

从 for 循环中的多个连续异步调用中调用多个“setState”挂钩

在for-each-loop中等待异步调用[重复]

在 for 循环中的异步函数调用中有条件地执行回调

如何在异步函数中处理多个等待

在 iOS 中等待多个网络异步调用