在下面的代码中,我是否处于回调状态?如何在不使用纯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 )阅读其他模块的例子
至于你应该使用异步库,你可以而且应该弥补自己的心态有关,但 后 你知道,知道非常好,这些每一个方法:
任何认真的node.js开发人员都知道如何在 所有 这些范例中使用和工作。是的,每个人都有其偏爱的方法,或者对不偏爱的方法有一些疑惑,但是这些都不是困难的,并且在无法决定您从头开始编写的一些不平凡的代码的情况下很难做出决定每个范例。另外,您应该尝试一些帮助程序库,并了解它们的工作方式以及为什么它们会为您节省样板。研究蒂姆·卡斯韦尔Step或考兰·麦克马洪的作品async将很有启发性。你看过everyauth源代码对promise的使用?我个人不喜欢它,但我肯定必须承认作者已经从该库中挤出了几乎所有重复的内容,而他使用诺言的方式会使您的大脑变成椒盐脆饼。这些人是有很多知识的巫师。不要仅仅因为时髦点而嘲笑那些图书馆。
Step
async
everyauth
还有一个很好的外部资源是callbackhell.com。