我的节点js模块中有一个以下对象,名为data:
{
"item_uuid": "77306c44-4175-4aee-866d-d8df89fa3ii9",
"accounts": [{
"accountid": "B15501",
"quantity": 1
},
{
"accountid": "S20000",
"quantity": 1
}]
}
我需要在传递整个数据以供进一步处理之前,通过将accountid传递给API来填充帐户中的每个帐户和国家/地区代码。
所以我循环帐户中的每个帐户并执行以下操作:
data.accounts.forEach(function(account) {
var clientAPI = "http://0.0.0.0:3000/" + account.accountid + "/?fields=country";
request.get(clientAPI, function (err, response, body) {
if (err) {
console.log("Unable to get country code for " +
account.accountid + " : " + err.message);
} else {
var clientData = JSON.parse(body);
account.country_code = clientData.country
}
})
}
// once all accounts have got country code, perform insertion into database
processData(data);
不幸的是,对clientAPI的调用是异步的,它不会等待返回结果,因此当数据到达processData时,它仍然没有country_code。
所以我在这里尝试瀑布:
var waterfall = require('async-waterfall');
waterfall([
function (callback) {
data.accounts.forEach(function(account) {
var clientAPI = "http://0.0.0.0:3000/" + account.accountid + "/?fields=country";
request.get(clientAPI, function (err, response, body) {
if (err) {
console.log("Unable to get country code for " + account.accountid + " : " + err.message);
} else {
var clientData = JSON.parse(body);
account.country_code = clientData.country
}
})
}
callback(null, data);
}
], function(err, data){
processData(data);
})
太糟糕了,它仍然不起作用,当涉及到processData(数据)时,它仍然没有country_code。
在这里使用瀑布,我错过了什么?除了在processData(数据)之前填充country_code,我还能做些什么呢?
我必须调用API来获取每个帐户的country_code。
答案 0 :(得分:1)
尝试promises(也许是节点7.6+中新的await / async语法),它们会产生更清晰,更符合逻辑的代码流。
const Promise = require('bluebird')
const request = Promise.promisifyAll(require('request'))
function getData(data){
return Promise.each(data.accounts, function(account){
const clientAPI = {
method: 'GET',
json: true,
uri: `http://0.0.0.0:3000/${account.accountid}/?fields=country`,
}
return request.getAsync(clientAPI).then(function(response){
if (!response.body.country) throw new Error('No country on '+account.accountid')
account.country_code = response.body.country
})
.catch(function(err){
console.error('Unable to get country code for '+account.accountid+' : '+err.message, err);
})
})
}
getData(data).then(function(){ processData(data) })
你也可以使用Promise.map
一些并发而不是串行的Promise.each
,并等待每个请求完成后再转移到下一个请求。
不捕获错误(或重新抛出err
)将导致Promise被拒绝而不是仅仅记录,这可能对程序更有用。 Promises的好处是错误会冒出来,所以你可以在程序/调用开始时以更全局的方式处理错误。
答案 1 :(得分:0)
如果您使用promises,async / await或生成器语法,这将更好地实现。
使用回调功能,使用计数器变量来跟踪您发送的请求数量,并在致电processData
之前等待计数器达到某个值。
let counter = 0;
data.accounts.forEach(function(account) {
var clientAPI = "http://0.0.0.0:3000/" + account.accountid + "/?fields=country";
request.get(clientAPI, function (err, response, body) {
if (err) {
console.log("Unable to get country code for " +
account.accountid + " : " + err.message);
counter++
} else {
var clientData = JSON.parse(body);
account.country_code = clientData.country
counter++
}
})
}
// once all accounts have got country code, perform insertion into database
if (counter === data.accounts.length) processData(data);