简体   繁体   English

Node.js Api在异步循环中调用

[英]Node.js Api calls in an Async loop

I'm having difficulty making multiple api calls and getting the returned results in the right place. 我很难进行多次api调用并将返回的结果放在正确的位置。 This what I'm trying to achieve: Two loops, nested. 这就是我想要实现的:两个循环,嵌套。 The outer loop loops over a complex json object and places some object's values in an array call box. 外部循环遍历复杂的json对象,并将一些对象的值放在数组调用框中。 The inner loop calls the api and the places the returned results in an array named bag. 内部循环调用api并将返回的结果放在名为bag的数组中。 So I have box and bag full of data. 所以我的盒子和包里装满了数据。 When both loops and api calls end, I would like to have access to the data in both box and bag and do stuff with it. 当循环和api调用都结束时,我希望能够访问盒子和包中的数据并使用它进行操作。 I'm just not sure of the best way to go have access to both arrays at the same point in execution. 我只是不确定在执行的同一点上访问两个数组的最佳方法。 This is what I have so far, but of course bag and box are empty because they get called before all the loops and api calls end. 这是我到目前为止所拥有的,但当然包和盒子都是空的,因为它们在所有循环和api调用结束之前被调用。

var data = {}//a json object with data;
var bag = [];
var box = [];

async.forEach(data.item, function(item, callback){

    async.forEach(item.name, function(name, callback){

        callApi(item.name, function(obj){

           bag.push(obj);
        });

        callback();

    }

   box.push(item);
   callback();

});


function callApi(name, callback){

    asyncApiCall(url+name, function(err, result){

        callback(result);       
    });

}

//when all loops and api requests are done
//do stuff with contents of box and bag here;
console.log(bag, box);

You can use a counter to ensure all async calls have returned and then call a callback. 您可以使用计数器确保已返回所有异步调用,然后调用回调。 An example: 一个例子:

function performAsyncOperation(data, onCompletion) {
    var bag = [];
    var box = [];
    var count  = 0;

    async.forEach(data.item, function(item, callback){
        async.forEach(item.name, function(name, callback){
            count += 1;
            callApi(item.name, function(obj){
               bag.push(obj);
               count -= 1;
               if (count == 0) {
                   onCompletion(null, { bag:bag, box:box });
               }
            });
            callback();
        }
       box.push(item);
       callback();
    });
}

count and onCompletion are the important parts above. countonCompletion是上面的重要部分。

Since you have the full dataset, you should first (synchronously) gather the list of names into one single array. 由于您拥有完整的数据集,因此应首先(同步)将名称列表收集到一个数组中。

Then, only do one level of async.forEach . 然后,只做一个级别的async.forEach Trying to do this with two level is unnecessary and results in more complex code. 尝试使用两个级别执行此操作是不必要的,并导致更复杂的代码。

If what you refer to as async is what you get using npm install async , here's a piece of code that illustrates what you could use (uses lodash to build the list of names, as this tends to be more consise. 如果你指的是什么async是你使用的是什么npm install async ,这里有一段代码,说明你可以使用的(使用lodash构建名称列表,因为这往往是更consise。

var _ = require("lodash");
var async = require("async");

var data = {
  item: [
    {name: "a"},
    {name: "b"}
  ]
};

var bag = [];

var items = _(_(data.item).collect(function(item) {
  return item.name;
})).value();

async.eachSeries(items, function(name, cb) {
  callApi(name, function(obj) {
    bag.push(obj);
    cb();
  });
}, function done() {
  console.log("bag", bag);
});

function callApi(name, cb) {
  cb(name);
}

And the output is: 输出是:

bag [ 'a', 'b' ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM