javascript Node.js - 在继续代码之前等待多个异步调用完成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/50924814/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 09:19:47  来源:igfitidea点击:

Node.js - Wait for multiple async calls to finish before continuing in code

javascriptnode.jsloopsasynchronousnpm

提问by Rxchard

So basically i have a for loop with an async function in it. Problem is that the program just continues after the loop and i want it to wait until all async functions which were called in the loop are finished before the code continues.

所以基本上我有一个带有异步函数的 for 循环。问题是程序只是在循环之后继续,我希望它等到循环中调用的所有异步函数都完成后再继续执行代码。

In my code "bar" is a json array with other json arrays in it.

在我的代码中,“bar”是一个 json 数组,其中包含其他 json 数组。

function write(bla) { // gets called one after another

  for(var url in bla) {
    asyncFunctionCall(url); // Executed about 50 times, it has to run parallel
  }
  // Wait for all called functions to finish before next stuff happens and
  // write gets called again.

}

for(var foo in bar) {
  // Here i parse the json array "foo" which is in the json array "bar"
  write(foo[bla]); // bla is an array of multiple urls.
}

The async function call looks something like this:

异步函数调用如下所示:

var request = require('request');

request(url, function (error, response, body) {
  if(typeof response !== 'undefined') {
    if((response.statusCode >= 400 && response.statusCode <= 451)
    || (response.statusCode >= 500 && response.statusCode <= 511))
      return true;
    return false;
  }
  return false;
});

回答by T.J. Crowder

The simplest way here is to use promises, directly or via async/awaitsyntax. In this case, probably directly.

这里最简单的方法是直接或通过async/await语法使用 Promise 。在这种情况下,可能直接。

First, you have to make asyncFunctionCallreturn a promise. It looks like you always return a boolean, so in this case we'll always resolve the promise:

首先,你必须让asyncFunctionCallreturn 成为一个承诺。看起来你总是返回一个布尔值,所以在这种情况下,我们将始终解决承诺:

function asyncFunctionCall(url) {
  return new Promise(resolve => {
    request(url, function (error, response, body) {
      if(typeof response !== 'undefined') {
        if((response.statusCode >= 400 && response.statusCode <= 451)
        || (response.statusCode >= 500 && response.statusCode <= 511)) {
          resolve(true);
          return;
        }
      }
      resolve(false);
    });
  });
}

Then, build up an array of your promises, and use Promise.allto wait for all of them to complete. These calls run in parallel:

然后,建立一系列您的承诺,并使用Promise.all等待所有承诺完成。这些调用并行运行:

function write(bla) { // gets called one after another
  const promises = [];
  for(var url in bla) {
    promises.push(asyncFunctionCall(url)); // Executed about 50 times.
  }
  return Promise.all(promises);
}

Then you can build a chain of all of the promises from writeso they run in series:

然后,您可以构建所有承诺的链,write以便它们串联运行:

let p = Promise.resolve();
for (const foo in bar) { // <== Notice `const`
  // See "Edit" below
  p = p.then(() => {
    // Here i parse the json object "foo" in the json array "bar"
    // bla is an array of multiple urls.
    return write(foo[bla]));
  });
}

Note that it's important that you use constor let, not var, for fooin that loop, because the thencallback closes over it; see this question's answersfor why constand letmake that work.

请注意,在该循环中使用constorlet而不是varfor很重要foo,因为then回调会关闭它;请参阅此问题的答案以了解原因constlet使其发挥作用。

Each call to writewill only be made when the previous one's work is done.

每次调用write只会在前一个工作完成时进行。

Then wait for the whole process to complete:

然后等待整个过程完成:

p.then(() => {
  // All done
});

You haven't shown anything usingthe booleans from write's requests, but they're available (as an array) as the resolution value of the promise from write.

您没有使用来自write的请求的布尔值显示任何内容,但它们可以(作为数组)作为来自 的承诺的分辨率值write



The second part of the process, where we're calling write, can also be written in an asyncfunction which may make the logical flow clearer:

过程的第二部分,我们正在调用write,也可以写在一个async函数中,这可能会使逻辑流程更清晰:

async function doTheWrites() {
  for (const foo in bar) {
    // Here i parse the json object "foo" in the json array "bar"
    // bla is an array of multiple urls.
    await write(foo[bla]);
  }
}

Then the overall process:

那么整体流程:

doTheWrites().then(() => {
  // All done
});

...or if this is alsoin an asyncfunction:

...或者如果这也在一个async函数中:

await doTheWrites();

回答by Jonas Wilms

Make the functions async and await the calls:

使函数异步并等待调用:

async function write(foo) {
   for(const url of foo) {
      await asyncFunctionCall(url);
   }  
}

(async function() {
   for(const foo of bar) {
     await  write(foo);
   }
})()

That will execute one request after another. To execute them on parallel use Promise.all:

这将执行一个又一个的请求。要并行执行它们,请使用 Promise.all:

const write = foo => Promise.all(foo.map(asyncFunctionCall));

Promise.all(bar.map(write))
  .then(() => console.log("all done"));