当前位置: 首页 > 面试题库 >

在Node.js中回调地狱?

梁丘璞瑜
2023-03-14
问题内容

在下面的代码中,我是否处于回调状态?如何在不使用纯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());
    }

问题答案:

是的,您处于回调地狱。假设您不想使用异步的解决方案(我怀疑您可以证明除偏见之外的其他理由)包括:

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. 诺言
  4. 帮助程序库(异步,步进,灵活等)

任何认真的node.js开发人员都知道如何在 所有
这些范例中使用和工作。是的,每个人都有其偏爱的方法,或者对不偏爱的方法有一些疑惑,但是这些都不是困难的,并且在无法决定您从头开始编写的一些不平凡的代码的情况下很难做出决定每个范例。另外,您应该尝试一些帮助程序库,并了解它们的工作方式以及为什么它们会为您节省样板。研究蒂姆·卡斯韦尔Step或考兰·麦克马洪的作品async将很有启发性。你看过everyauth源代码对promise的使用?我个人不喜欢它,但我肯定必须承认作者已经从该库中挤出了几乎所有重复的内容,而他使用诺言的方式会使您的大脑变成椒盐脆饼。这些人是有很多知识的巫师。不要仅仅因为时髦点而嘲笑那些图书馆。

还有一个很好的外部资源是callbackhell.com。



 类似资料:
  • 主要内容:阻塞代码实例,非阻塞代码实例Node.js 异步编程的直接体现就是回调。 异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。 回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。 例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js

  • Node.js 异步编程的直接体现就是回调。 异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。 回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。 例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js

  • 问题内容: 我在从Node.js中的回调函数返回值时遇到了小麻烦,我将尝试尽可能轻松地解释我的情况。考虑一下我有一个片段,它包含URL,并命中该URL,并提供输出: 我试图将其包装在函数中并返回如下值: 因为在我的Node.js代码中,我有很多语句将决定value的值,例如: 关键是a内的所有语句将保持相同,除了的值。因此,绝对需要将这些通用代码放入函数中。我尝试了同样的方法,但是in总是会回报我

  • 我的应用程序应该更新,如果tmx是新的,如果旧的什么都不做,如果不存在插入文件。如果文档被插入,它工作完美,否则它不能正确更新或说E11000 dup密钥。想弄清楚我的回调是不是错了还是逻辑。(我是node.js+MongoDB的新手)MongoClient=require(“MongoDB”).MongoClient,assert=require(“assert”),url=“MongoDB:/

  • 问题内容: 我试图用NodeJS编写代码,从外部API抓取数据,然后使用Mongoose在MongoDB中填充它们。在这之间,我将检查该特定对象是否已经存在于Mongo中。下面是我的代码。 我的问题是,由于NodeJS回调是并行的,因此不会按顺序调用它。我的最终结果将是这样的: 呼叫报告API console.log(长度)= 100 ^^^^^^^^^^^^^^^^^^^^^^^^^ conso

  • 问题内容: 我需要有关node.js异步特性的帮助。我有一个for循环,该循环从数据库收集数据。“结果”是一个数组,然后应将其返回到主函数。 如何确保循环完成后执行回调? 问题答案: 您可能要考虑使用帮助程序库,例如 异步 https://github.com/caolan/async 它有助于使代码更加一致。 就您而言,您可以查看forEach()方法 调用迭代器时,将使用列表中的项目以及完成时