2014-05-06 2 views
2

SO.Traitement du rappel des appels asynchrones

J'ai une question concernant le traitement des appels asynchrones Windows Azure Mobile Services à une base de données Azure. En ce moment, je poste un objet avec un tableau que je boucle à son tour dans mon point de terminaison WAMS api.

La boucle récupère l'objet actuel dans le tableau et le place avec un ID unique dans la base de données. Cela retourne l'identifiant de la ligne de la dernière ligne insérée, et dans le rappel, je récupère ceci et instancie un autre appel asynchrone.
Ici, j'insère le dernier identifiant de ligne inséré, avec un tas de propriétés de l'objet dans la boucle actuelle du tableau.

Cependant, cela semble se comporter bizarrement, et insérer la même information dans toutes les colonnes de mon deuxième appel asynchrone.

for (var i = 0; i < object.array.length; i++) { 

    var mssql = request.service.mssql, 
     prop1 = object.array[i].prop1, 
     prop2 = object.array[i].prop2, 
     user = object.user.userid; 

    mssql.query("exec stored_procedure ?, ?", [user, prop1], { 
     success: function (res) { 

      var insertedid = res[0]; 

      if (typeof insertedid === 'undefined') { 
       return; 
      } else { 
       insertedid = insertedid.ID; 
      } 

      mssql.query("exec stored_procedure_2 ?, ?", [insertedid, prop2], { 

       //success 

      }); 

     } 
    }); 
} 

que je fais sans doute quelque chose de complètement faux, parce que je ne pas tout à fait ce que j'ai produit, mais compte tenu de ma familiarité Node.js, ce fut elle.

Répondre

2

Voici une implémentation possible avec async.js. Si vous avez plus de deux propriétés, vous devrez générer les fonctions "insertPropX" dynamiquement, mais cela devrait vous aider à démarrer.

var mssql = request.service.mssql; 
var user = object.user; 

function insertProp1(obj, cb) { 
    mssql.query("exec stored_procedure ?, ?", [user.userid, obj.prop1], { 
    success: function (res) { 
     var inserted = res[0]; 
     if (!inserted) { 
      return cb('prop1 not inserted for userid: ' + user.userid); 
     } 
     // pass the ID and the object to the next 
     // function in the "waterfall" chain 
     cb(null, inserted.ID, obj); 
    } 
    }); 
} 

function insertProp2(id, obj, cb) { 
    mssql.query("exec stored_procedure_2 ?, ?", [id, obj.prop2], { 
    success: function (res) { 
     var inserted = res[0]; 
     if (!inserted) { 
     return cb('prop2 not inserted for id: ' + id); 
     } 
     // since this is the last function in 
     // the "waterfall" chain, we don't need 
     // to pass anything along 
     cb(null); 
    } 
    }); 
} 

// for each object in the array... 
async.each(object.array, function iterator (obj, cb) { 
    // insert properties in order, passing the 
    // insertion ID as an argument 
    async.waterfall([ 
    insertProp1.bind(null, obj), 
    insertProp2 
    ], cb); 
}, function allDone (err) { 
    if (err) { 
    console.log(err); 
    } 
    // all done 
}); 
+0

Merci pour cette réponse complète, cela m'a donné les connaissances que je devais voir le modèle de la façon dont il doit être fait. J'ai up arrow'd les deux réponses ici, mais le vôtre a gagné ma bonne réponse. Donc, la fonction de rappel dans la première tâche asynchrone transmet l'information à l'itération suivante que je prends? – NicT

+1

Content de pouvoir aider. Correct, chaque fonction de la cascade transmet des arguments à la fonction suivante. Je vous recommande vivement de regarder la bibliothèque async.js en profondeur, car elle a aussi beaucoup d'autres fonctionnalités impressionnantes. –

+0

Problèmes de définition des arguments à transmettre aux fonctions de la cascade. J'ai quelques arguments de plus que dans l'exemple que j'ai montré ci-dessus. Il y a 4 arguments que je dois passer à chacun d'entre eux à chaque itération de async.each. Je Logging les arguments quand ils sont passés, incorrecte var async.each (interaction.Locs, fonction (interaction.CID, emplacement, uname, org, cb) { async.waterfall ( [ insertCL.bind (null, interaction.ControlID, localisation, uname, org), insertLOQ ], cb ); } – NicT

2

La boucle s'exécute plus rapidement que les requêtes externes terminent et effectuent leurs rappels. Par conséquent, à mesure que chaque rappel s'exécute, ils utilisent tous la valeur actuelle (et finale) de i plutôt que la valeur lorsque la requête externe est exécutée.

Ceci est illustré par une boucle simple comme celui qui montre ce qui se passe:

for (var i = 0; i < 10; i++) { 
    setTimeout(function(){ 
     console.log('the value for i is', i); 
    },100); 
} 

Vous verrez que ce petit programme n'imprime pas une séquence, mais plutôt ce 10 fois:

the value for i is 10 

L'utilisation promises (listes plusieurs bibliothèques ou options) ou un outil comme async (lien vers la page GitHub) sont deux possibilités si des solutions à ce problème.

+0

+1 pour async.js –

Questions connexes