Node.js 使用nodejs如何返回包含循环中一批API调用中所有数据的对象?
我知道JavaScript中有闭包和回调,但很明显,我没有直观地理解它们 我有一个从API中抓取数据的小应用程序,我可以轻松地Node.js 使用nodejs如何返回包含循环中一批API调用中所有数据的对象?,node.js,callback,Node.js,Callback,我知道JavaScript中有闭包和回调,但很明显,我没有直观地理解它们 我有一个从API中抓取数据的小应用程序,我可以轻松地控制台。记录每个请求的响应,我的问题是我试图收集数据并构建一个对象,以便在所有请求完成后保存到文件中 我知道nodejs是一个执行的单线程,它不会阻塞,但我不知道在所有内部请求完成后将回调放在哪里,我可以console.logbuilded对象。您将看到我的控制台。日志行位于错误的位置,并在来自内部请求的第一个响应之前执行 细分 获取国家数据 循环countryRespo
控制台。记录每个请求的响应,我的问题是我试图收集数据并构建一个对象,以便在所有请求完成后保存到文件中
我知道nodejs是一个执行的单线程,它不会阻塞,但我不知道在所有内部请求完成后将回调放在哪里,我可以console.log
builded对象。您将看到我的控制台。日志
行位于错误的位置,并在来自内部请求的第一个响应之前执行
细分
获取国家数据
循环countryResponse并使用每个国家id获取详细信息
将每个细节添加到数组中
当所有请求完成时,将数组添加到对象
代码
const limit = require("simple-rate-limiter");
let request = limit(require("request")).to(1).per(200);
let options = {
method: 'POST',
url: 'https://myendpoint/details',
headers: {
'cache-control': 'no-cache',
'Content-Type': 'application/json'
},
body: {
"token": "TOKEN",
"method": "countries"
},
json: true
};
global.package = {};
global.services = {};
let countryServices = [];
/*
Country fetch
*/
request(options, function (err, response, countryResponse) {
if (err) {}
package.countries = countryResponse;
countryResponse.forEach(function (entry) {
let innerOptions = {
method: 'POST',
url: 'https://myendpoint/details',
headers: {
'cache-control': 'no-cache',
'Content-Type': 'application/json'
},
body: {
"token": "TOKEN",
"method": "services"
},
json: true
};
//THIS LINE OMG
//let countryServices = [];
innerOptions.body.countryCode = entry.countryCode;
request(innerOptions, function (err, response, innerResponse) {
if (err) {}
countryServices.push(innerResponse);
console.log(" inner response " + entry.countryCode + ' : ' + JSON.stringify(innerResponse, null, ""));
});//END innerResponse
});//END countryResponse.forEach
services = countryServices;
console.log(JSON.stringify(package, null, ""));
console.log(JSON.stringify(countryServices, null, ""));
});//END orderResponse
[
{
"countryCode": 1,
"countryName": "Virgin Islands (U.S.)"
},
{
"countryCode": 7,
"countryName": "Russian Federation"
}
]
[
{
"Type": "1",
"id": 2
},
{
"Type": "2",
"id": 3
}
]
countryResponse
const limit = require("simple-rate-limiter");
let request = limit(require("request")).to(1).per(200);
let options = {
method: 'POST',
url: 'https://myendpoint/details',
headers: {
'cache-control': 'no-cache',
'Content-Type': 'application/json'
},
body: {
"token": "TOKEN",
"method": "countries"
},
json: true
};
global.package = {};
global.services = {};
let countryServices = [];
/*
Country fetch
*/
request(options, function (err, response, countryResponse) {
if (err) {}
package.countries = countryResponse;
countryResponse.forEach(function (entry) {
let innerOptions = {
method: 'POST',
url: 'https://myendpoint/details',
headers: {
'cache-control': 'no-cache',
'Content-Type': 'application/json'
},
body: {
"token": "TOKEN",
"method": "services"
},
json: true
};
//THIS LINE OMG
//let countryServices = [];
innerOptions.body.countryCode = entry.countryCode;
request(innerOptions, function (err, response, innerResponse) {
if (err) {}
countryServices.push(innerResponse);
console.log(" inner response " + entry.countryCode + ' : ' + JSON.stringify(innerResponse, null, ""));
});//END innerResponse
});//END countryResponse.forEach
services = countryServices;
console.log(JSON.stringify(package, null, ""));
console.log(JSON.stringify(countryServices, null, ""));
});//END orderResponse
[
{
"countryCode": 1,
"countryName": "Virgin Islands (U.S.)"
},
{
"countryCode": 7,
"countryName": "Russian Federation"
}
]
[
{
"Type": "1",
"id": 2
},
{
"Type": "2",
"id": 3
}
]
内部响应
const limit = require("simple-rate-limiter");
let request = limit(require("request")).to(1).per(200);
let options = {
method: 'POST',
url: 'https://myendpoint/details',
headers: {
'cache-control': 'no-cache',
'Content-Type': 'application/json'
},
body: {
"token": "TOKEN",
"method": "countries"
},
json: true
};
global.package = {};
global.services = {};
let countryServices = [];
/*
Country fetch
*/
request(options, function (err, response, countryResponse) {
if (err) {}
package.countries = countryResponse;
countryResponse.forEach(function (entry) {
let innerOptions = {
method: 'POST',
url: 'https://myendpoint/details',
headers: {
'cache-control': 'no-cache',
'Content-Type': 'application/json'
},
body: {
"token": "TOKEN",
"method": "services"
},
json: true
};
//THIS LINE OMG
//let countryServices = [];
innerOptions.body.countryCode = entry.countryCode;
request(innerOptions, function (err, response, innerResponse) {
if (err) {}
countryServices.push(innerResponse);
console.log(" inner response " + entry.countryCode + ' : ' + JSON.stringify(innerResponse, null, ""));
});//END innerResponse
});//END countryResponse.forEach
services = countryServices;
console.log(JSON.stringify(package, null, ""));
console.log(JSON.stringify(countryServices, null, ""));
});//END orderResponse
[
{
"countryCode": 1,
"countryName": "Virgin Islands (U.S.)"
},
{
"countryCode": 7,
"countryName": "Russian Federation"
}
]
[
{
"Type": "1",
"id": 2
},
{
"Type": "2",
"id": 3
}
]
最简洁、最直接的方法可能是async/await
way。您可以手动提示请求
并用简单延迟替换简单速率限制器
相关性:
“严格使用”;
const request=require('request');
功能承诺请求(选项){
返回新承诺((解决、拒绝)=>{
请求(选项,(错误、响应、正文)=>{
如果(错误)拒绝(错误);
其他决议(机构);
});
});
}
功能延迟(毫秒){
返回新承诺((resolve)=>{setTimeout(resolve,ms);});
}
常量选项={
方法:“POST”,
网址:'https://myendpoint/details',
标题:{
“缓存控制”:“无缓存”,
“内容类型”:“应用程序/json”,
},
正文:{
令牌:“令牌”,
方法:“国家”,
},
是的,
};
(异步函数main(){
试一试{
const countryResponse=等待承诺请求(选项);
常量innerRequests=[];
for(countryResponse的常量输入){
常量innerOptions={
方法:“POST”,
网址:'https://myendpoint/details',
标题:{
“缓存控制”:“无缓存”,
“内容类型”:“应用程序/json”,
},
正文:{
令牌:“令牌”,
方法:“服务”,
countryCode:entry.countryCode,
},
是的,
};
const innerRequest=promisifiedRequest(innerOptions);
innerRequests.push(innerRequest);
等待延迟(200);
}
const countryServices=wait Promise.all(内部请求);
log(JSON.stringify(countryServices,null');
}捕捉(错误){
控制台错误(err);
}
})();
如果您需要更多背景信息或需要扩展应用程序(添加具有更复杂速率限制的并行请求),这些资料将非常有用:
代码末尾的控制台.log
s不会等到forEach
启动的所有异步操作完成后才运行。您需要引入某种机制,等待forEach触发的所有函数完成它们的请求
如果您想坚持使用回调,那么可以考虑使用类似的each
方法,它将为您处理这种情况
通常使用和来处理此问题。如果您使用的是,您的示例将如下所示,假设Node.js的版本相当最新(选项省略):
const request=require('request-promise');
异步函数run(){
常量选项={};
const countryServices=[];
const countryResponse=等待请求(选项);
for(const country of countryResponse){
const innerOptions={};
const innerResponse=等待请求(innerOptions);
countryServices.push(内部响应);
}
console.log(countryServices);
}
run();
这比使用回调要清楚一点,for-of循环的行为完全符合您的预期。谢谢您,我肯定有很多东西需要学习,我看到了很多阅读材料。我注意到一件事,在我天真的方法中,它完成了运行约19秒,但您的解决方案是约85秒。这是因为您的请求是异步的,只有在前一个请求完成+200ms延迟后才会发出请求;像我这样的人,每200毫秒会在哪里发出一次请求?是的。我可以尝试编辑以实现相同的行为。稍后我会添加一条评论。你能尝试一下新的变体并做一些小的改动吗?是的,最多20秒!:)我花了一分钟才看到您构建了一个promisifiedRequest
s数组,然后调用了Promise。所有这些都是。非常感谢,我有很多事情要考虑,并将根据响应添加更多嵌套调用。@chrisloughnane Happy coding)