【问题标题】:Node.js Api calls in an Async loopNode.js Api 在异步循环中调用
【发布时间】:2013-02-16 16:40:36
【问题描述】:

我很难进行多次 api 调用并将返回的结果放在正确的位置。这就是我想要实现的:两个循环,嵌套。外部循环遍历一个复杂的 json 对象,并将一些对象的值放在一个数组调用框中。内部循环调用 api 并将返回的结果放在名为 bag 的数组中。所以我有装满数据的盒子和袋子。当循环和 api 调用都结束时,我想访问 box 和 bag 中的数据并用它做一些事情。我只是不确定在执行的同一点访问两个数组的最佳方法。这是我到目前为止所拥有的,但当然 bag 和 box 是空的,因为它们在所有循环和 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);

【问题讨论】:

  • async是不是引用了曹岚的Async库?
  • 如果真的是草兰Async,那可不是这么用的。 Async 的 Github page 有很好的例子
  • @BrandonTilley 是的 Caolan 的异步

标签: javascript node.js asynchronous foreach callback


【解决方案1】:

您可以使用计数器来确保所有异步调用都已返回,然后调用回调。一个例子:

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();
    });
}

countonCompletion 是上面的重要部分。

【讨论】:

  • 我可以立即看到它是如何工作的。它确实奏效了。但是,我不喜欢到处都是旗帜。对我来说,这个解决方案的整体积极方面是习惯于思考回调。
【解决方案2】:

由于您拥有完整的数据集,您应该首先(同步)将名称列表收集到一个数组中。

然后,只做一级async.forEach。尝试使用两个级别来执行此操作是不必要的,并且会导致更复杂的代码。

如果您所指的 async 是您使用 npm install async 得到的,这里有一段代码说明您可以使用什么(使用 lodash 构建名称列表,因为这往往更多言简意赅。

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);
}

输出是:

bag [ 'a', 'b' ]

【讨论】:

  • +1 表示 lodash,因为我一直在使用下划线。另外我认为这是一个很好的方法,但由于我的数据对象的复杂性,我仍然需要嵌套循环。
猜你喜欢
  • 2017-06-16
  • 2020-07-03
  • 1970-01-01
  • 2015-02-27
  • 1970-01-01
  • 2011-11-08
  • 2015-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多