Node.js 中的回调地狱

Posted

技术标签:

【中文标题】Node.js 中的回调地狱【英文标题】:Callback hell in Node.js 【发布时间】:2017-01-01 20:13:28 【问题描述】:

我在 Node.js 中遇到了“回调地狱”的情况。

基本上我想要的是:

从静态 json 文件中读取数据(本地) --> 查询 MongoDB 以从两个单独的集合中获取两条记录 --> 比较返回的数据 -> 将比较后的结果添加到结果对象中 --> 进入下一步在循环中 --> 重复。

请检查代码,让我知道问题出在哪里。

 jsonfile.readFile(file, function(err, staticData) 
if(err)
  console.log("Error while loading Tower Details from Static Data " + err);

else
  var staticD = staticData.Teams;
  var l = staticData.Teams.length;
 // console.log('*******************Getting Tower Level Data from Static File*******************');
  //console.log('*******************Tower Name received is ******************* ' + staticData.Tower);
      if(counter == l)
        console.log('Inside the couneter loop');
       res.json(testObject);
      
  for ( var i = 0 ; i<l; i++)
   var trackName = staticD[i].name
   console.log('Counter--------->>>>' + counter);
    //console.log("Team name " + staticD[i].name);
        ++counter;
    for (var j = 0 ; j<staticD[i].applications.length;j++)
     //var RObj;
     //var AObj;
      //console.log("Application Name " + staticD[i].applications[j]);
      var applicationName = staticD[i].applications[j];
      var test = new Object();
      test.data =  [];
      var resultSet;

     var response = reference.find('appname' : applicationName , 'track' : trackName ).sort('_id': -1);
     var promise = response.exec();
     var alertT = alert.find('appname' : applicationName , 'track' : trackName ).sort('_id': -1).limit(1);
     var promise1 = alertT.exec();

        promise.then(function allRefRecords (recordAlerts)
         if(recordAlerts.length >0)
          //console.log('Ref Length' + recordAlerts.length);
        recordAlerts.forEach(function refRecord(R)
          testObject.data.testInfra.push(R);
          //console.log('testObject' + testObject.data.testInfra);
          );
    

          );

        promise1.then(function allAlertsRecords (alerts)
          if(alerts.length > 0)
        alerts.forEach(function refRecord(a)
        // console.log('a' + a)
         testObject.data.testCustom.push(a);
          //console.log('testObject' + testObject.data.testCustom);
         // res.json(testObject);

       );
                 
          )
        .then(function()
           resultSet = compareData(testObject.data.testCustom,testObject.data.testInfra);
           test.data.push(resultSet);
          )
        .then(function()
          res.json(test);
        );
    

  



);

);

【问题讨论】:

我会建议你在你的代码中使用async,而不是使用for循环。 我已经尝试了代码中的承诺,但是我得到了可变的结果。有时我会收到 2 条记录,有时会收到 3 条记录。 【参考方案1】:

不要嵌套函数,给它们命名并将它们放在顶层 你的程序。使用功能提升来移动 功能“首屏”。处理每一个错误中的每一个错误 您的回调并使用类似标准的 linter 来帮助您 这。创建可重用的函数并将它们放在一个模块中以减少 理解代码所需的认知负荷。拆分你的 像这样将代码分成小块也可以帮助您处理错误,编写 测试,迫使您创建一个稳定且记录在案的公共 API 您的代码,并有助于重构。

来源:http://callbackhell.com/

使用异步、承诺、设计和许多其他方式可以避免回调地狱...... 但是 99% 的时间,设计是最好的(恕我直言),你不需要其他东西。

一些链接:How to Elegantly Solve the Callback HellAvoiding Callback Hell in Node.js

记住回调地狱不是致命的;)

【讨论】:

我已经在代码中尝试过承诺,现在我得到了结果。但是,结果中的记录数是随机的。这意味着有时我会收到 2 条记录,有时会收到 3 条记录,这是对同一请求的响应。我想要的是:从参考集合中获取一条记录,然后从警报集合中获取一条记录,然后比较在上一步中获取的两个对象并返回结果。我也在添加代码 sn-ps。 代码片段#1 response = reference.find('appname' : applicationName , 'track' : trackName ).sort('_id': -1);变种承诺;承诺 = response.exec();变量警报T; alertT = alert.find('appname' : applicationName , 'track' : trackName ).sort('_id': -1).limit(1);变种承诺1; promise1 = alertT.exec(); 代码片段#2 : promise.then(function allRefRecords (recordAlerts) if(recordAlerts.length == 1) recordAlerts.forEach(function refRecord(R) testObject.data.testInfra.push (R); ); ); 代码片段#3 : promise1.then(function allAlertsRecords (alerts) itemProcessed++; if(alerts.length == 1) alerts.forEach(function refRecord(a) testObject.data.testCustom .push(a); resultSet = compareData(testObject.data.testCustom,testObject.data.testInfra); returnObject.data.push(resultSet); ); if(itemProcessed == parseInt(total)) res.json (returnObject); ); 添加您在问题中尝试过的代码。【参考方案2】:

一些防止进一步出现回调地狱的提示,您可以浏览下一个库:

Async.js:您可以连续执行函数而无需嵌套它们。 Bluebird:通过映射和排队,异步逻辑将更易于管理。 问:揭示了 promise 的概念,可以毫不费力地管理嵌套调用。

【讨论】:

以上是关于Node.js 中的回调地狱的主要内容,如果未能解决你的问题,请参考以下文章

Node.js回调地狱及使用Promiseasync和await函数的解决方法

Node.js Promise对象(解决回调地狱问题)async和await函数

告别回调地狱,在Node里优雅的访问MySQL

如何使用async.js简化Node.js中的回调代码

把 Node.js 中的回调转换为 Promise

Node.js服务器开发(下)