简体   繁体   English

Node.js-等待多个异步调用完成,然后继续执行代码

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

So basically i have a for loop with an async function in it. 所以基本上我有一个带有异步功能的for循环。 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. 问题是程序在循环后才继续,我希望它等待直到在循环中被调用的所有异步函数都完成,然后代码才能继续。

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

The simplest way here is to use promises, directly or via async / await syntax. 这里最简单的方法是直接或通过async / await语法使用promise。 In this case, probably directly. 在这种情况下,可能直接。

First, you have to make asyncFunctionCall return a promise. 首先,您必须使asyncFunctionCall返回承诺。 It looks like you always return a boolean, so in this case we'll always resolve the promise: 看来您总是返回一个布尔值,因此在这种情况下,我们将始终兑现承诺:

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.all to wait for all of them to complete. 然后,建立您的诺言数组,并使用Promise.all等待所有诺言完成。 These calls run in parallel : 这些调用并行运行:

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 write so 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 const or let , not var , for foo in that loop, because the then callback closes over it; 请注意,在该循环中对foo使用constlet而不是var是很重要的,因为then回调会关闭它。 see this question's answers for why const and let make that work. 看到这个问题的答案,为什么constlet ,使这项工作。

Each call to write will 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 using the booleans from write 's requests, but they're available (as an array) as the resolution value of the promise from write . 您还没有使用 write请求中的布尔值显示任何内容,但是它们可以(作为数组)作为来自write的promise的分辨率值使用。


The second part of the process, where we're calling write , can also be written in an async function 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 also in an async function: ...或者如果这也在 async函数中:

await doTheWrites();

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

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

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