首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在for循环(Node.JS)中处理回调

如何在for循环(Node.JS)中处理回调
EN

Stack Overflow用户
提问于 2015-03-30 09:51:44
回答 2查看 889关注 0票数 0

我试图用NodeJS编写一个代码,从中获取外部API中的数据,然后使用Mongoose在MongoDB中填充它们。在此期间,我将检查这个特殊情况是否已经存在于蒙戈。下面是我的密码。

代码语言:javascript
复制
router.route('/report') // the REST api address
  .post(function(req, res) // calling a POST 
  {
    console.log('calling report API');
    var object = "report/" + reportID; // related to the API
    var parameters = '&limit=100' // related to the API
    var url = link + object + apiKey + parameters; // related to the API

    var data = "";
    https.get(url, function callback(response)
    {
      response.setEncoding("utf8");
      response.on("data", function(chunk)
      {
        data += chunk.toString() + ""; 
      });

      response.on("end", function()
      {
        var jsonData = JSON.parse(data);
        var array = jsonData['results']; // data is return in array of objects. accessing only a particular array
        var length = array.length;
        console.log(length);

        for (var i = 0; i < length; i++) 
        {
          var report = new Report(array.pop()); // Report is the schema model defined. 
          console.log('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^');
          console.log(i);
          console.log('*****************************');
          console.log(report);
          console.log('*****************************');
          // console.log(report['id']);

          /*report.save(function(err)
          {
            if(err)
              res.send(err);
          });*/

          Report.find({id:report['id']}).count(function(err, count) // checks if the id of that specific data already exists in Mongo
          {
            console.log(count);
            console.log('*****************************');
            if (count == 0) // if the count = 0, meaning not exist, then only save
            {
              report.save(function(err)
              {
                console.log('saved');
                if(err)
                  res.send(err);
              });
            }
          });
        };
        res.json({
                    message: 'Grabbed Report'
                  }); 
      });
      response.on("error", console.error);
    });
  })

我的问题是,由于NodeJS回调是并行的,所以不会按顺序调用。我的最终结果会是这样的:

  1. 调用报表API
  2. Console.log(长度)= 100
  3. ^
  4. console.log(i) =以0开头
  5. *
  6. console.log(report) =将存储在蒙古族内部的数据
  7. *
  8. 当长度等于100时,数字3-7重复100次。
  9. Console.log(计数)=0或1
  10. 数字9重复100次
  11. Console.log(“保存”)
  12. 数字11重复100次
  13. 最后,100个数据中只有最后一个被存储到Mongo中。

我需要的是某种技术或方法来处理这些回调,这些回调是一个接一个地执行,而不是按照循环顺序执行。我很确定这就是问题所在,因为我的其他REST都在工作。

我已经研究过异步方法、承诺、递归函数以及其他一些我能真正理解如何解决这个问题的方法。我真希望有人能对这件事有所了解。

如果我问问题的方式有任何错误,也可以纠正我。这是我在StackOverflow上发布的第一个问题。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-03-30 14:48:00

这个问题被称为“回调地狱”。还有很多其他方法,比如使用承诺异步库。

我对本机ES7将带来的更多的兴奋,您可以在今天开始使用它,并使用转换程序库巴贝尔

但到目前为止,我发现的最简单的方法是:取出长回调函数并在外部定义它们。

代码语言:javascript
复制
router.route('/report') // the REST api address
    .post(calling_a_POST)

function calling_a_POST(req, res) {
    ...
    var data = "";
    https.get(url, function callback(response) {
        ...
        response.on("end", response_on_end_callback); // --> take out
        response.on("error", console.error);
    });
}

function response_on_end_callback() {                 // <-- define here
    ...
    for (var i = 0; i < length; i++) {
        var report = new Report(array.pop());
        ...
        Report.find({ id: report['id'] })
              .count(Report_find_count_callback);     // --> take out
    };
    res.json({
        message: 'Grabbed Report'
    });
}

function Report_find_count_callback(err, count) {     // <-- define here
    ...
    if (count == 0) {
        report.save(function(err) {                   // !! report is undefined here
            console.log('saved');
            if (err)
                res.send(err);                        // !! res is undefined here
        });
    }
}

请注意,您将无法访问以前的回调中的所有变量,因为您已经将它们从作用域中删除。

这可以通过一个类型的“依赖注入”包装器来解决,以传递所需的变量。

代码语言:javascript
复制
router.route('/report') // the REST api address
    .post(calling_a_POST)

function calling_a_POST(req, res) {
    ...
    var data = "";
    https.get(url, function callback(response) {
        ...
        response.on("end", function(err, data){       // take these arguments
            response_on_end(err, data, res);          // plus the needed variables
        });
        response.on("error", console.error);
    });
}

function response_on_end(err, data, res) {  // and pass them to function defined outside
    ...
    for (var i = 0; i < length; i++) {
        var report = new Report(array.pop());
        ...
        Report.find({ id: report['id'] })
            .count(function(err, count){
                Report_find_count(err, count, report, res);  // same here
            });
    };
    res.json({                                        // res is now available
        message: 'Grabbed Report'
    });
}

function Report_find_count(err, count, report, res) {        // same here
    ...
    if (count == 0) {
        report.save(function(err) {                   // report is now available
            console.log('saved');
            if (err)
                res.send(err);                        // res is now available
        });
    }
}

当我执行response_on_end函数时,我得到了undefined:1 unexpected token u错误。我很确定这与这一行有关:var jsonData = JSON.parse(data)我的response_on_end如下所示:var jsonData = JSON.parse(data); // problem here

我意识到我犯了一个错误:

代码语言:javascript
复制
function calling_a_POST(req, res) {
    ...
    var data = "";
    https.get(url, function callback(response) {
        ...
        //sponse.on("end", function(err, data){
        response.on("end", function(err){ // data shouldn't be here
            response_on_end(err, data, res);
        });
        response.on("error", console.error);
    });
}

另一个我可以忽略的问题,这个问题实际上可能不会在这里出现,但还是最好还是谈一谈。data变量,因为它是一个与对象不同的原始类型的字符串,所以它是“通过值传递的”。更多信息

最好将变量包装在对象中并传递对象,因为javascript中的对象总是“通过引用传递”。

代码语言:javascript
复制
function calling_a_POST(req, res) {
    ...
    // var data = ""; // 
    var data_wrapper = {};
    data_wrapper.data = {};                                // wrap it in an object
    https.get(url, function callback(response) {
        ...
        response.on("data", function(chunk){
            data_wrapper.data += chunk.toString() + "";   // use the dot notation to reference
        });
        response.on("end", function(err){ 
            response_on_end(err, data_wrapper, res);      // and pass that object
        });
        response.on("error", console.error);
    });
}

function response_on_end_callback(err, data_wrapper, res) {
    var data = data_wrapper.data;                         // later redefine the variable
    ...
    for (var i = 0; i < length; i++) {
        var report = new Report(array.pop());
        ...
票数 5
EN

Stack Overflow用户

发布于 2015-03-30 11:43:58

您可以使用异步库来控制执行流。还有用于处理数组的迭代器。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29343116

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档