这里是Node.js的新手。我正在寻找从另一个函数中进行N个异步API调用的正确方法,并将它们的结果组合起来以便进一步使用下游。在我的情况下,N会相当小并且阻止它们的执行也不会太糟糕。
在同步执行中,下面的combine()的实现应该有效。
如果我只需要一次API调用的结果,那么在提供给callAPI()的回调函数中实现以下逻辑将是直截了当的。我绊倒的地方是在执行foo之前我需要所有结果的时候(总计,[... args])。
我调查了async.whilst
,但无法让它发挥作用。如果这实际上符合我的需要,我会持怀疑态度。我也调查了Promises
这似乎是正确的领导,但在爬进那个巨大的兔子洞之前获得再保证会很好。是Promises
是正确的方法,哪个模块是Node.js
项目中使用的标准?
var http = require('http');
function callAPI(id) {
var options = {
host: 'example.com',
path: '/q/result/'.concat(id)
}
var req = http.get(options, (res) => {
var body = [];
res.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
return body;
}).on('error', (err) => {
console.error(err);
});
});
}
function combine(inputs) {
var total = 0;
for (i=0; i < inputs.length; i++) {
total += callAPI(inputs[i]['id']);
};
console.log(total);
// call some function, foo(total, [...args])
}
编辑1:
我尝试按照下面的samanime的回答修改API调用以返回Promise。参见:
function callAPI(id) {
return Promise((resolve, reject) => {
var options = {
host: 'example.com',
path: '/q/result/'.concat(id)
}
var req = http.get(options, (res) => {
var body = [];
res.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
resolve(body);
}).on('error', (err) => {
reject(err);
});
});
});
}
function combine(inputs) {
var combined = [];
for (i=0; i < inputs.length; i++) {
total += callAPI(inputs[i]['id']);
.then(result => {
combined.push(result);
});
};
var total = combined.reduce((a, b) => a + b, 0);
console.log(total);
// call some function, foo(total, [...args])
}
这似乎让我半途而废。如果我在console.log(combined)
块中then()
,我可以看到列表中包含来自API调用的结果。但是,我仍然无法在&#34; end&#34;访问完整的combined
。 for
循环。在构建完整列表后,我可以将回调附加到要运行的内容吗?还有更好的方法吗?
编辑2(我的解决方案 - 根据Patrick Roberts的建议)
function callAPI(id) {
return Promise((resolve, reject) => {
var options = {
host: 'example.com',
path: '/q/result/'.concat(id)
}
var req = http.get(options, (res) => {
var body = [];
res.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = parseInt(Buffer.concat(body));
resolve(body);
}).on('error', (err) => {
reject(err);
});
});
});
}
function combine(inputs) {
var combined = [];
Promise.all(inputs.map(input => callAPI(input.id)))
.then((combined) => {
var total = combined.reduce((a, b) => a + b, 0);
// foo(total, [...args])
});
};
答案 0 :(得分:2)
听起来你可以将一堆承诺链接在一起,传递数据。
基本上类似于:
const combined = [];
asyncOne()
.then(result => { combined.push(result); return asyncTwo())
.then(result => { combined.push(result); return asyncThree())
// and so on
只要每个函数都返回一个promise,你就可以全部设置。
如果您想并行运行它们,请使用Promise.all()
,这将为您做同样的事情:
Promise.all([asyncOne(), asyncTwo(), asyncThree() /* , etc */])
.then(combined => /* combined is an array with the results of each */)
到目前为止,这是此类事情的首选模式。
答案 1 :(得分:0)
你的编辑看起来好多了,但试试这个:
function callAPI(id) {
return Promise((resolve, reject) => {
var options = {
host: 'example.com',
path: '/q/result/' + id
}
http.get(options, (res) => {
var body = [];
res.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
resolve(body);
}).on('error', reject);
});
});
}
function combine(inputs) {
Promise.all(inputs.map(input => callAPI(input.id))).then((combined) => {
// completed array of bodies
console.log(combined);
// foo(combined.length, [...args]);
}).catch((error) => {
console.log(error);
});
}
答案 2 :(得分:-1)
我会添加一个计数器来跟踪剩余的API调用。每当API调用完成,减少,如果它为0,你就完成了。
const numCalls = 10;
let remaining = numCalls;
let data = [];
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
function ajax() {
// Simulate ajax with a setTimeout for random amount of time.
setTimeout(() => {
// This is the callback when calling http.get
data.push(getRandomInt(0, 10)); // Some data from server
if (--remaining <= 0) {
// Am I the last call? Use data.
console.log(data);
console.log(data.length);
}
}, getRandomInt(1000, 3000));
}
for (let i = 0; i < numCalls; i++) {
ajax();
}
&#13;