0

ノードモジュールに3つのネストされたコールバックのセットである関数があり、ネストされた各コールバックは前のコールバックのデータに依存するため、必要な線形性が得られ、見事に機能します。問題は、2番目の関数のコールバックがバブルアップし、その親関数を再帰的に呼び出す必要があることです。外部APIと通信します。これが実際のコードで、変数の名前が変更されて、私のスーパートップのsekritビジネスロジックがわかりにくくなっています。

exports.account_usage = function (req, res) {

  var domainID = req.body.domains,
    startDate = req.body.date_start,
    endDate = req.body.date_end,
    accountItems = {},
    usage = {},
    domainStats = {},
    page = 0;
  //req.cs is a module that communicates with an external API to gather usage data
  req.cs.exec("listAccountItems", {
    "listall": "true",
      "domainid": domainID
  },

  function (error, result) {
    accountItems = result.item;
    console.log("listAccountItems callback");

    //Get Usage Records

    req.cs.exec("listUsageRecords", {
      "startdate": startDate,
        "enddate": endDate,
        "domainid": domainID,
        "page": page,
        "pagesize": 2000 //try not to DDOS the server. only fetch 2000 records at a time
    }, function (error, result) {
      usage = req._.extend(usage, result.usagerecord); //this is underscore
      console.log("Usage Records: " + usage.length);
      page++;
      //right here, if result.length === 2000, I need to call
      // listUsageRecords until result.length < 2000

      //got list of  Usage,
      //now process usage here

      //filter usage item 1
      var bytesrecords1 = req._.filter(usage, function (usage) {
        return (usage.usagetype === 4);
      });
      //sum
      var bytes1 = req._.reduce(bytesrecords1, function (memo, record) {
        return memo + parseInt(record.rawusage, 10);
      }, 0);
      console.log("Bytes1: " + bytes1);
      domainStats.bytes1 = (((bytes1 / 1000) / 1000) / 1000).toFixed(4);

      //filter usage item 2
      var bytesrecords2 = req._.filter(usage, function (usage) {
        return (usage.usagetype === 5);
      });
      //sum
      var bytes2 = req._.reduce(bytesrecords2, function (memo, record) {
        return memo + parseInt(record.rawusage, 10);
      }, 0);
      console.log("Bytes2: " + bytes2);
      domainStats.bytes2 = (((bytes2 / 1000) / 1000) / 1000).toFixed(4);

      req._.each(accountItems, function (account) {
        //get runnning hours
        var recs = req._.filter(usage, function (usage) {
          return (usage.accountid === account.id && usage.usagetype === 1);
        });
        account.usage = req._.reduce(recs, function (memo, record) {
          return memo + parseInt(record.rawusage, 10);
        }, 0);

        //filter all the recs for each usage type, 1-14
        console.log("Account Usage: " + account.usage);
        console.log("Account ID: " + account.name);
      });


      console.log("ready to render");
      res.render('usage', {
        "title": "Usage Report",
        "domain": domainStats
      });


    });
  });


};

実際のコードもこのフィドルに含まれています:[http://jsfiddle.net/3wTQA/1/] [1]指が出血するまでGoogleを使用しましたが、代わりに内部コールバックが続行されないようにする方法がわかりません。繰り返しの。フェッチする必要のある大きなデータセットの場合にリモートシステムでDDOSを防ぐために、APIは外部APIからのページングを必要とします。

編集:これは、注釈を付けてサニタイズした実際のコードであり、抽出しようとしているデータの例がいくつかあります:http: //jsfiddle.net/3wTQA/1/

4

2 に答える 2

1

わかりました、私はそれを働かせました。async.whilst 関数を使用して、すべてのデータがフェッチされるまでコールバック内にとどまりました。ここに私がそれをした方法があります:

exports.account_usage = function (req, res) {

  var domainID = req.body.domains,
    startDate = req.body.date_start,
    endDate = req.body.date_end,
    accountItems = {},
    usage = {},
    domainStats = {},
    page = 0;
  //req.cs is a module that communicates with an external API to gather usage data
  req.cs.exec("listAccountItems", {
    "listall": "true",
      "domainid": domainID
  },

  function (error, result) {
    accountItems = result.item;
    console.log("listAccountItems callback");

    //Get Usage Records
async.whilst(
function(){return count === pagesize},
function (callback){
    req.cs.exec("listUsageRecords", {
      "startdate": startDate,
        "enddate": endDate,
        "domainid": domainID,
        "page": page,
        "pagesize": 2000 //try not to DDOS the server. only fetch 2000 records at a time
    }, function (error, result) {
       usage.usagerecord = usage.usagerecord.concat(result.usagerecord);
       count = result.usagerecord.length;

      console.log("Usage Records: " + usage.length);
      page++;
      callback();
      //now process usage here
},
function (err) {
      //filter usage item 1
      var bytesrecords1 = req._.filter(usage, function (usage) {
        return (usage.usagetype === 4);
      });
      //sum
      var bytes1 = req._.reduce(bytesrecords1, function (memo, record) {
        return memo + parseInt(record.rawusage, 10);
      }, 0);
      console.log("Bytes1: " + bytes1);
      domainStats.bytes1 = (((bytes1 / 1000) / 1000) / 1000).toFixed(4);

      //filter usage item 2
      var bytesrecords2 = req._.filter(usage, function (usage) {
        return (usage.usagetype === 5);
      });
      //sum
      var bytes2 = req._.reduce(bytesrecords2, function (memo, record) {
        return memo + parseInt(record.rawusage, 10);
      }, 0);
      console.log("Bytes2: " + bytes2);
      domainStats.bytes2 = (((bytes2 / 1000) / 1000) / 1000).toFixed(4);

      req._.each(accountItems, function (account) {
        //get runnning hours
        var recs = req._.filter(usage, function (usage) {
          return (usage.accountid === account.id && usage.usagetype === 1);
        });
        account.usage = req._.reduce(recs, function (memo, record) {
          return memo + parseInt(record.rawusage, 10);
        }, 0);

        //filter all the recs for each usage type, 1-14
        console.log("Account Usage: " + account.usage);
        console.log("Account ID: " + account.name);
      });


      console.log("ready to render");
      res.render('usage', {
        "title": "Usage Report",
        "domain": domainStats
      });


    });
  });
}),

};
于 2013-01-13T16:10:05.027 に答える
0

pagesを含むクロージャ内で関数を分割できると思いますbiglistofresults

biglistofresults = {};
function pages(id, page) {
    page = page || 0;
    module.exec("anotherAPIcall", {"id": id, "page": page }, 
        function (error, result) {
            if (result.length === 2000) { //there is probably more data
                biglistofresults = _.extend(biglistofresults, result);
                pages(id, page + 1);
            }
    );
}
module.exec("externalAPIcall", {"listall": "true", "domainid": domainID}, 
    function (error, result) {
        _.map(result, pages);
});
于 2013-01-12T02:27:59.233 に答える