12
votes

Enfil de rappel dans Nodejs?

dans le code ci-dessous suis-je dans callbackhell? Comment surmonter un tel scénario sans utiliser de modules ASYNC dans Pure JavaScript? XXX

Le code ci-dessus est copié dans plusieurs emplacements pour faire fonctionner le code comme prévu. xxx


2 commentaires

Pourquoi avez-vous besoin de l'essai / attraper? Normalement, des erreurs sont transmises au rappel, et cela devrait couper le niveau d'indentation de moitié


Pour répondre à la moitié de la question: Oui, vous êtes en enfer de rappel. Vous voudrez probablement présenter une certaine abstraction; Si vous êtes opposé aux bibliothèques de contrôle de contrôle existantes, vous voudrez probablement que vous souhaitiez probablement écrire une fonction de la série vous-même.


3 Réponses :


31
votes

Oui, vous êtes en enfer de rappel. La solution supposant que vous ne voulez pas utiliser ASYNC (que je doute que vous puissiez justifier autrement que le préjudice) consiste en:

1 fort>) fait plus de fonctions de niveau supérieur. Chaque fonction doit effectuer 1 ou 2 opérations IO en règle générale. P>

2 strong>) Appelez ces fonctions, ce qui fait que votre code suive une structure d'une longue liste de fonctions de base courtes Organisé en logique commerciale par une petite liste de flux de contrôle «Colle» fonctions. p>

au lieu de: p> xxx pré>

objectif pour: p>

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}


6 commentaires

Je suppose que je devrais utiliser la bibliothèque Async.


Il est bon de savoir comment utiliser des rappels simples sans entrer en enfer. Apprenez ensuite à utiliser les événements de base pour obtenir des résultats similaires, le cas échéant. Ensuite, considérons des promesses. Mais en fin de compte lors de la rédaction d'une application Web et que chaque requête implique généralement 3 opérations d'E / S qui doivent être effectuées en série ou en parallèle, oui, vous voulez probablement apprendre à utiliser une bibliothèque de flux de contrôle telle que ASYNC, Nimble, étape, ou similaire.


Bonjour, devrais-je utiliser async.servies ou async.fall dans cette condition?


J'ai un argument pourquoi je n'utilise pas ASYNC ni d'autres bibliothèques d'assistance telles que le soulignement ou les promesses. Ces 3 libs, pour moi, polluent le code. Vanilla JS est simple, facile, vous n'avez pas besoin d'utiliser une fonction de boîte noire pour exécuter des fonctions asynchrones «parallèles», il vous suffit de comprendre comment travailler. Si vous organisez votre code, vous n'avez pas besoin de boîtes noires pour des trucs faciles comme ça.


@askkirati commence par série & cascade car ils sont plus faciles à comprendre. Finalement, lorsque vous comprenez les vraies dépendances ou l'absence de ceux-ci entre vos opérations, vous pouvez passer à parallèle et peut-être une vitesse de certaines choses.


Dans la section "Viser" ", j'aimerais y voir un exemple. Mon expérience est que j'aimerais concevoir cela, mais quand je le fais, BusinessLogic () est exécuté avant sauvegardéb1 () est terminé.



8
votes

"Si vous essayez de coder BussSiness DB Connectez-vous en utilisant pur nœud.js, vous allez directement à Callback Hell" em>

J'ai récemment créé une abstraction simple nommée waitfor pour appeler des fonctions asynchrones Mode synchronisé (basé sur des fibres): https://github.com/luciotato/waitfor P>

Vérifiez l'exemple de la base de données: P>

Exemple de base de données (pseudocode) h2>

pure nœud.js (HELLE de rappel léger): p>

//run in a Fiber
function processInviteEmails(email_list, user_id, emailCallBack, completionCallback){

    while (email_list.length) {

      var email = email_list.pop();

      try {

          check(email).isEmail(); //is valid email or throw

          var connected_data = wait.for(checkConnected,email,user_id);
          if(connected_data.connect_status !== 'not connected') throw new Error('Already connected');

          //insert to connect and send msg to queue
          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
          };

          result = wait.forMethod(ConnectModel,'insert',dbData);
          // ConnectModel.insert shuold have a fn(err,data) as callback, and return something in err if (data.insertId <= 0) 

          //send to email queue
          //Queue Email
          res_data = wait.forMethod(MailTemplateModel,'getTemplateData','invitation');
          // MailTemplateModel.getTemplateData shuold have a fn(err,data) as callback
          // inside getTemplateData, callback with err=new Error('Unable to get email template') if (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 ... callback(err,data)
          wait.forMethod(sqsHelper,'addToQueue',cfg.sqs_invitation_url, mailOptions); 

      } catch (e) {
          // one of the callback returned err!==null 
          emailCallBack(e, email);
      }

    } // loop while length>0

    completionCallback();

  }

  // run the loop in a Fiber (keep node spinning)
  wait.launchFiber(processInviteEmails,email_list, user_id, emailCallBack, completionCallback);


0 commentaires