node.js - nodejs中的回调 hell ?

标签 node.js callback

在下面的代码中我是在回调 hell 吗?如何在不使用纯 javascript 中的任何异步模块的情况下克服这种情况?

emailCallBack(e_data, email);
if (email_list.length) {
  checkEmail(email_list.pop());
} else {
  completionCallback();
}

以上代码被复制到多个位置,以使代码按预期工作。

function processInviteEmails(email_list, user_id, emailCallBack, completionCallback){
      function checkEmail(email){
        try {
          check(email).isEmail();
          //is valid email
          checkConnected(email, user_id, function(connect_status, user_row, user_meta_row, connect_row){
            var e_data;
            //insert to connect and send msg to queue
            if(connect_status === 'not connected'){
              var cur_date = moment().format('YYYY-MM-DD');
              var dbData = {
                "first_name": '',
                "last_name": '',
                "email": email,
                "user_id": user_id,
                "status": "invited",
                "unsubscribe_token": crypto.randomBytes(6).toString('base64'),
                "created": cur_date,
                "modified": cur_date
              };
              ConnectModel.insert(dbData, function(result){
                if (result.insertId > 0) {
                  //send to email queue
                  //Queue Email
                  MailTemplateModel.getTemplateData('invitation', function(res_data){
                    if(res_data.status === 'success'){
                      var unsubscribe_hash = crypto.createHash("md5")
                        .update(dbData.unsubscribe_token + email)
                        .digest('hex');
                      var unsubscribe_link = app.locals.SITE_URL+'/unsubscribe/' + result.insertId + '/' + unsubscribe_hash;
                      var template_row = res_data.template_row;
                      var user_full_name = user_row.user_firstname+' '+ user_row.user_lastname;
                      var invitation_link = 'http://'+user_row.url_alias+'.'+ app.locals.SITE_DOMAIN;
                      var mailOptions = {
                        "type": 'invitation',
                        "to": dbData.email,
                        "from_name" : user_full_name,
                        "subject": template_row.message_subject
                          .replace('[[USER]]',  user_full_name),
                        "text": template_row.message_text_body
                          .replace('[[USER]]', user_full_name)
                          .replace('[[INVITATION_LINK]]', invitation_link)
                          .replace('[[UNSUBSCRIBE_LINK]]', unsubscribe_link),
                        "html": template_row.message_body
                          .replace('[[USER]]', user_full_name)
                          .replace('[[INVITATION_LINK]]', invitation_link)
                          .replace('[[UNSUBSCRIBE_LINK]]', unsubscribe_link)
                      };
                      mailOptions = JSON.stringify(mailOptions);
                      //send email to queue
                      sqsHelper.addToQueue(cfg.sqs_invitation_url, mailOptions, function(data){
                        if(data){
                          e_data = null;
                        }
                        else{
                          e_data = new Error('Unable to Queue ');
                        }
                        emailCallBack(e_data, email);
                        if (email_list.length) {
                          checkEmail(email_list.pop());
                        } else {
                          completionCallback();
                        }
                      });
                    }
                    else{
                      e_data = new Error('Unable to get email template');
                      emailCallBack(e_data, email);
                      if (email_list.length) {
                        checkEmail(email_list.pop());
                      } else {
                        completionCallback();
                      }
                    }
                  });
                }
                else{
                  e_data = new Error('Unable to Insert connect');
                  emailCallBack(e_data, email);
                  if (email_list.length) {
                    checkEmail(email_list.pop());
                  } else {
                    completionCallback();
                  }
                }
              });
            }
            else{
              e_data = new Error('Already connected');
              emailCallBack(e_data, email);
              if (email_list.length) {
                checkEmail(email_list.pop());
              } else {
                completionCallback();
              }
            }
          });
        } catch (e) {
          //invalid email
          emailCallBack(e, email);
          if (email_list.length) {
            checkEmail(email_list.pop());
          } else {
            completionCallback();
          }
        }
      }
      checkEmail(email_list.pop());
    }

最佳答案

是的,您正处于回调 hell 中。假设您不想使用 async 的解决方案(我怀疑您可以证明除偏见之外的合理性)包括:

1) 制作更多顶级函数。根据经验,每个函数应该执行 1 或 2 次 IO 操作。

2) 调用这些函数,使您的代码遵循由一小部分控制流“粘合”函数组织成业务逻辑的一长串短核心函数的模式。

代替:

saveDb1 //lots of code
  saveDb2 //lots of code
    sendEmail //lots of code

目标:

function saveDb1(arg1, arg2, callback) {//top-level code}
function saveDb2(arg1, arg2, callback) {//top-level code}
function sendEmail(arg1, arg2, callback) {//top-level code}
function businessLogic(){//uses the above to get the work done}

3) 使用更多的函数参数而不是过多地依赖闭包

4) 发出事件并解耦你的代码!看看您是如何将代码嵌套到数据库中,然后构建电子邮件并将其添加到队列中的?难道你没有看到这两个不需要一个在另一个之上存在吗?电子邮件非常适合用于发送事件的核心业务逻辑以及监听这些事件和排队邮件的电子邮件模块。

5) 将应用级服务连接代码与特定事务业务逻辑解耦。处理与网络服务的连接应该更广泛地处理,而不是嵌入特定的业务逻辑集。

6) 阅读其他模块的示例

至于你是否应该使用异步库,你可以而且应该自己决定,但是之后你知道并且非常了解这些方法中的每一种:

  1. 回调和基本的函数式 JavaScript 技术
  2. 事件
  3. promise
  4. 辅助库(异步、步进、灵活等)

任何认真的 node.js 开发人员都知道如何在所有这些范例中使用和工作。是的,每个人都有自己喜欢的方法,也许对不喜欢的方法有些 Nerd 气,但这些都不难,如果不能指出你从头开始编写的一些非平凡的代码,就下定决心做出决定是很糟糕的每个范式。此外,您应该尝试几个帮助程序库并了解它们是如何工作的以及为什么它们会为您节省样板文件。研究 Tim Caswell 的 Step 或 Caolan McMahon 的 async 的工作会很有启发性。你见过 everyauth 源代码对 promises 的使用吗?我个人不喜欢它,但我必须承认作者已经从该库中挤出了几乎所有重复的内容,他使用 promise 的方式会将你的大脑变成椒盐脆饼。这些人是有很多要教的巫师。不要仅仅为了时髦点或其他什么而 mock 那些图书馆。

callbackhell.com 也是一个很好的外部资源.

关于node.js - nodejs中的回调 hell ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18095107/

相关文章:

javascript - 理解 JavaScript 中的术语迭代器、回调、函数工厂

node.js - 处理 CronJob 执行函数中的错误

node.js - 从 package.json 中的源代码编译

node.js - 箭头功能在 Ubuntu 下的 Node --harmony 中不起作用

javascript - Angular $http.get 不传递参数

c++ - 使用类成员函数作为回调

javascript - 如何向指定 channel 发送消息?

javascript - 用于多个连接的 DRY 解决方案?

c - 如何检查 libcurl 回调内的 HTTP 状态?

c++具有每个实例化对象的特定功能的结构(或类)