nodejs中的回调地狱? [英] Callback hell in nodejs?

查看:20
本文介绍了nodejs中的回调地狱?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In below code am I in callbackhell? How to overcome such scenario without using any async modules in pure javascript?

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

将以上代码复制到多个位置以使代码按预期工作.

The above code is copied in multiple location to make code work as expected.

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());
    }

推荐答案

是的,您正处于回调地狱中.假设您不想使用异步的解决方案(我怀疑除了偏见之外,您是否可以证明这一点)包括:

Yes you are in callback hell. The solution assuming you don't want to use async (which I doubt you can justify other than prejudice) consists of:

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

1) Make more top-level functions. Each function should perform either 1 or 2 IO operations as a rule of thumb.

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

2) Call those functions, making your code follow a pattern of a long list of short core functions organized into business logic by a small list of control flow "glue" functions.

代替:

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) 使用更多的函数参数,而不是过分依赖闭包

3) Use more function arguments instead of relying so much on closures

4) 发出事件并解耦您的代码!看看您如何嵌套代码将内容写入数据库,然后构建电子邮件并将其添加到队列中?难道你不明白这两者是如何不需要一个叠在另一个之上的吗?电子邮件非常适合发出事件的核心业务逻辑和侦听这些事件并对邮件进行排队的电子邮件模块.

4) Emit events and DECOUPLE YOUR CODE! See how you have nested code writing stuff to the database and then building an email and adding it to a queue? Don't you see how those two do not need to exist one on top of the other? Emails lend themselves very well to a core business logic emitting events and an email module listening to those events and queueing the mail.

5) 将应用程序级服务连接代码与特定事务业务逻辑分离.处理与网络服务的连接应该更广泛地处理,而不是嵌入一组特定的业务逻辑.

5) Decouple application-level service connection code from specific transaction business logic. Dealing with connections to network services should be handled more broadly and not embedded with a specific set of business logic.

6) 阅读其他模块的示例

6) Read other modules for examples

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

As to should you use an async library, you can and should make up your own mind about that but AFTER you know, and know pretty well, each and every one of these approaches:

  1. 回调和基本的函数式 javascript 技术
  2. 活动
  3. 承诺
  4. 辅助库(异步、步进、敏捷等)

任何认真的 node.js 开发人员都知道如何在所有范式中使用和工作.是的,每个人都有自己喜欢的方法,也许对不受欢迎的方法有些书呆子的愤怒,但是这些都不难,而且在无法指出您从头开始编写的一些重要代码的情况下做出决定是不好的每个范式.此外,您应该尝试几个帮助程序库并了解它们的工作原理以及为什么它们会为您节省样板.研究 Tim Caswell 的 Step 或 Caolan McMahon 的 async 的工作将非常有启发性.你见过 everyauth 源代码对 promise 的使用吗?我个人不喜欢它,但我肯定不得不承认,作者几乎从那个库中挤出了最后一点重复,而且他使用 Promise 的方式会让你的大脑变成椒盐脆饼.这些人是有很多东西要教的巫师.不要为了时髦点或其他什么而嘲笑那些图书馆.

Any serious node.js developer knows how to use and work within ALL of those paradigms. Yes, everyone has their favored approach and maybe some nerd rage about the non-favored approaches, but none of these are difficult and it's bad to get set in your decision without being able to point to some non-trivial code you wrote from scratch in each paradigm. Also, you should try several helper libraries and understand how they work and why they are going to save you boilerplate. Studying the work of Tim Caswell's Step or Caolan McMahon's async is going to be very enlightening. Have you seen the everyauth source code's use of promises? I don't like it personally but I surely have to admit that the author has squeezed damn near every last bit of repetition out of that library, and the way he uses promises will turn your brain into a pretzel. These people are wizards with much to teach. Don't scoff at those libraries just for hipster points or whatever.

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

Also a good external resource is callbackhell.com.

这篇关于nodejs中的回调地狱?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆