【问题标题】:Callback hell in Node.jsNode.js 中的回调地狱
【发布时间】:2026-02-08 13:40:01
【问题描述】:

我在 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 条记录。

标签: javascript node.js mongodb asynchronous


【解决方案1】:

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

来源:http://callbackhell.com/

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

一些链接:
How to Elegantly Solve the Callback Hell
Avoiding 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 的概念,可以毫不费力地管理嵌套调用。

【讨论】: