2
geturls(data,function(urls){
    var data = {
        "data": [
            { "userProfile": userP },
            { "urls": urls }
        ]
    };
    res.send(data);
});


function getUrls(data,done){

    links = new Array();

    for (var i=0; i<data.length; i++){
        user = data[i]
        Url.find({where:{data.id}}).success(function(url){
            links.push({
                "url": ur.text,
                "date": data.syncedTime
            });

            if (urls.length == data.length){
                done(links);
            }
        });
    }
}

我的代码的问题是:

一旦在我的数组中收集的数据等于父数组的长度,我将通过回调返回响应。这显然是一个非常危险且不那么优雅的解决方案。因为,假设我从 Url 数据库中得到一个 .failure,那么我的 urls.length 将不等于 data.length。所以,我有点困惑如何去做。有什么帮助吗?

4

4 回答 4

1

使用递归:

function getUrls(data,done) {
    var links = new Array();

    function doGetUrl(i) {
        var user = data[i];
        Url.find({where:{data.id}}).
        success(function(url){
            links.push({
                "url": ur.text,
                "date": data.syncedTime
            });

            if (links.length == data.length){
                done(links);
            } else {
                doGetUrl(i + 1); // get next url
            }
        }).
        failure(function(err) {    
            doGetUrl(i); // on error, try to get current url again
            // other error handling code
        });
    }

    doGetUrl(0);
}
于 2013-06-29T06:36:12.153 回答
1

如果您使用async.js.

mapSeries在这里用过。它需要3个参数。

  • 集合/数组
  • 迭代器,它将为传递的集合/数组中的每个项目调用 2 个参数。1. 集合中的项目,2. 回调。在迭代器中完成工作后,您应该以节点样式调用回调(先出错,然后是结果)。
  • 最终回调,将在集合中的所有项目映射后调用。

function getUrls(data,done){

  var async = require('async');

  async.mapSeries(data, function(user, cb) {//If you want it to be async `async.map`

    Url.find({where:{user.id}}).success(function(url){
      cb(null, {
            "url": url.text,
            "date": user.syncedTime
      });
    });
  }, function(err, results) {
    //results is an array. Its the same as `links` in your old code.
    done(results);
  });

}

geturls(data,function(urls){
  var data = {
    "data": [
        { "userProfile": userP },
        { "urls": urls }
    ]
  };
  res.send(data);
}); 
于 2013-06-29T07:19:08.003 回答
0

我可能会使用 jQuery 术语中的完整回调。有一个计数器记录已处理的记录数并完整更新,因为这会在成功或失败时执行。然后,当该计数器 >= 数据数组的长度时,您可以退出。

顺便说一句,对于您在那里进行的比较,我总是会使用 >= 而不是 ==,这样,如果出于任何疯狂的原因,计数会比您仍然退出时的计数增加更多。

于 2013-06-29T06:31:54.773 回答
0

如果您想要做的只是避免检查 links.length 以确定何时完成的问题,那么我认为这只是添加一个单独的计数器的问题,即使 urk 数据库失败,该计数器也会增加。如果这样做,您可以继续使用当前并行运行异步请求的 stype。

var nreq = 0;
for (var i=0; i<data.length; i++){
   doTheAsyncOperation(function(){
     //Run this part in both the success and error cases
     nreq = nreq + 1;
     if(nreq >= data.length){ done(links) }
   })
}

另一方面,如果您想一个接一个地运行一个查询,则需要重写 for 以使用递归。这一次,您无需担心保留单独的计数器,因为您知道最终请求何时运行:

function loop(i){
  if(i >= data.length){
    done(links);
  }else{
    doTheAsyncOperation(function(){
      loop(i+1);
    })
  }
}

loop(0);

最后,很高兴知道如何自己编写这种模式,但从长远来看,我强烈建议使用控制流库来让事情变得更简洁。

于 2013-06-29T07:25:30.947 回答