在 Node.js 中如何等待异步请求的 for 循环执行完成?

15

我想在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,但也没有起作用。那么如何等待这个循环完成获取请求并将它们推送到数组中,以便可以显示给用户呢?


附上带有async await的代码,它应该可以工作,或者使用sync-request库。 - bxN5
你可以使用 Promises:https://www.promisejs.org/ - César Ferreira
4个回答

27

根据您的用例,使用Promise.allawait可能是最有效的方法。 您的代码应该类似于:

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 (error) reject(error);
        else resolve(body)
    })
  }))
}
res.send(await Promise.all(promiseArray));

8

使用类似 request-promise 的工具。如果你在 for 循环中等待每个请求完成,那么所有请求都会按顺序依次执行。如果每个请求是独立的且不需要一个接一个地执行,这种方式效率较低。处理此类情况的最佳方法是并行执行所有请求,然后等待它们全部完成。这可以通过创建请求 promise 数组,然后使用 await Promise.all(promiseArray) 等待所有 promise 解析完成来实现。

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 Promise.all(promises);

默认情况下,request 不会返回一个 Promise。 - Ayush Gupta
这就是为什么我建议使用_request-promise_。 - Kon
啊,没关注文本,专注于代码了,抱歉。 - Ayush Gupta
太好了,兄弟。这很简单。 - Ramesh_D
使用 request-promise 确实可以使代码更加清晰易读。 - jet_choong

2

正如其他人所说,你应该在异步代码中使用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方法。

2
要使用async/await,您需要使用返回承诺而不是回调函数的HTTP库。
强烈建议使用可以实现此功能的库。另一个不错的选项是"node-fetch",它有效地实现了浏览器所实现的"Fetch API"。
然后,您只需简单地使用"await fetch(url)"命令即可。
async/await工作得非常好,并且正在变得如此普遍,我强烈建议切换到将其视为一流公民而不是片面考虑的框架和库。这包括Express,它也是一个基于回调的库,而不是基于承诺的库。但这略微偏题了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接