如何在node.js中等待带有异步请求的循环完成?

时间:2018-10-09 15:32:26

标签: node.js for-loop asynchronous

我想在node.js中发出多个请求,以获取几个外部API响应,并将它们组合为一个数组。我正在使用for循环来实现这一点。这是我的代码:

res.setHeader('Content-Type', 'application/json');
const sub = req.query.days_subtract;
const enddate = req.query.end_date; 

var array = [];

for (var i = 0; i < sub; i++) {
  request("https://api.nasa.gov/planetary/apod?date=" + subtractDate(enddate, i) + "&api_key=DEMO_KEY", function(error, response, body) {
    array.push(body); 
    // console.log(body);
  });
}
res.send(array);

但是这段代码始终返回[]。我知道这是因为for循环仅启动这些异步请求,但并不等待它们完成。我尝试使用async / await,但还是没有用。那么,如何等待此循环完成请求的获取并完成将请求推送到数组以便可以将其显示给用户呢?

4 个答案:

答案 0 :(得分:4)

对于您的用例,将awaitPromise.all一起使用可能是执行此操作最有效的方法。您的代码应如下所示:

res.setHeader('Content-Type', 'application/json');
const sub = req.query.days_subtract;
const enddate = req.query.end_date;

var promiseArray = [];

for (var i = 0; i < sub; i++) {
    promiseArray.push(new Promise((resolve, reject) => 
        request("https://api.nasa.gov/planetary/apod?date=" + subtractDate(enddate, i) + "&api_key=DEMO_KEY", function(error, response, body) {
        if (err) reject(err);
        resolve(body)
    })))
}
res.send(await Promise.all(promiseArray));

答案 1 :(得分:2)

要使用异步/等待,您需要使用一个返回promise的HTTP库,而不是使用回调。

使用可以执行此操作的库非常值得。 node-fetch是另一个库的不错选择,它可以有效地实现浏览器所实现的“提取API”。

然后您可以简单地await fetch(url)

async / await运作良好,并且变得司空见惯,我强烈建议您切换到将其视为一流公民而不是事后思考的框架和库。这包括Express,它也是基于回调的库,而不是基于Promise的库。但这有点题外话了。

答案 2 :(得分:2)

使用类似request-promise的名称。如果您在for循环中等待每个请求,那么所有请求将依次完成。如果每个请求都是独立的,不需要一个接一个地执行,则效率低下。处理此类问题的最佳方法是并行完成所有任务,然后等待所有任务完成。这是通过创建请求承诺数组然后使用await Promise.all(promiseArray)等待所有承诺解决来完成的。

var promises = [];

for (var i = 0; i < sub; i++) {
  const promise = request("https://api.nasa.gov/planetary/apod?date=" + subtractDate(enddate, i) + "&api_key=DEMO_KEY");
  promises.push(promise);
}

const array = await Promisea.all(promises);

答案 3 :(得分:1)

正如其他人所说,您可能应该将Promise用于异步代码,并且async / await语法非常清晰。

但是,您似乎更喜欢使用回调。在这种情况下,您可以这样编写代码:

res.setHeader('Content-Type', 'application/json');
const sub = req.query.days_subtract;
const enddate = req.query.end_date; 

var array = [];
var resultsCount = 0;

for (var i = 0; i < sub; i++) {
  request("https://api.nasa.gov/planetary/apod?date=" + subtractDate(enddate, i) + "&api_key=DEMO_KEY", function(error, response, body) {
    if (error) { res.status(500) }
    array[i] = body
    // console.log(body);
    resultCount++;
    if (resultCount === sub) {
      res.send(array);
    }
  });
}

基本上,该想法是仅在所有请求返回其结果后才调用res.send方法。

相关问题