Existe-t-il une approche purement promise pour la cartographie / concaténation des collections?

Async vs. Q en général

J'apprends le développement de Node.js et j'essaie d'envelopper mon cerveau autour des stratégies de gestion de l'enfer "rappel" asynchrone. Les deux stratégies principales que j'ai explorées sont le module asynchrone Caolan McMahon et le module Q basé sur les promesses de Kris Kowal.

Comme beaucoup d'autres personnes , je me moque toujours de comprendre quand vous devriez utiliser l'une contre l'autre. Cependant, d'une manière générale, j'ai trouvé que les promesses et le code basé sur Q étaient légèrement plus intuitifs, alors je me déplaçais dans cette direction.

Cartographier / concaténer des collections en général

Cependant, je suis toujours coincé en utilisant les fonctions du module async pour gérer les collections . En provenance d'un fond d'écran Java et Python, la plupart du temps, lorsque je travaille avec une collection, la logique ressemble à ceci:

  1. Initialiser une nouvelle collection vide, dans laquelle stocker les résultats.
  2. Effectuez une boucle pour-chaque avec l'ancienne collection, en appliquant une certaine logique à chaque élément et en poussant son résultat dans la nouvelle collection vide.
  3. Lorsque la boucle for-each se termine, utilisez la nouvelle collection.

Dans le JavaScript côté client, je me suis habituée à utiliser la fonction map () de jQuery … en passant dans cette logique # 2, et en obtenant la troisième étape comme valeur de retour. Se sent comme la même approche de base.

Mapping / Concatenant des collections avec Async et Q

Le module asynchimique à côté du noeud possède des fonctions de concat et de carte similaires, mais ils ne renvoient pas le résultat concaténé au niveau de l'étendue d'origine. Vous devez plutôt descendre dans l'enfer rappel pour utiliser le résultat. Exemple:

var deferred = Q.defer(); ... var entries = [???]; // some array of objects with "id" attributes async.concat(entries, function (entry, callback) { callback(null, entry.id); }, function (err, ids) { // We now have the "ids" array, holding the "id" attributes of all items in the "entries" array. ... // Optionaly, perhaps do some sorting or other post-processing on "ids". ... deferred.resolve(ids); }); ... return deferred.promise; 

Étant donné que mes autres fonctions deviennent prometteuses, j'ai ce code renvoyant un objet prometteur afin qu'il puisse être facilement inclus dans une chaîne then() .

Ai-je vraiment besoin de ces deux?

La question ultime que je m'efforce d'articuler est: ai-je vraiment besoin d'Async et de Q dans l'exemple de code ci-dessus? J'apprends à remplacer le flux de contrôle du module Async par des chaînes de promesses de type Q en général … mais il n'a pas encore "cliqué" sur ma façon de faire un cartographie ou une concaténation de collections avec une approche prometteuse. Alternativement, j'aimerais comprendre pourquoi vous ne pouvez pas, ou pourquoi ce n'est pas une bonne idée.

Si async et Q sont censés travailler ensemble alors que je les utilise dans l'exemple ci-dessus, alors que ce soit. Mais je préférerais ne pas exiger la dépendance supplémentaire de la bibliothèque si je pouvais utiliser Clean Q seul.

( Désolé si je manque quelque chose de scandaleusement évident. Le modèle asynchrone axé sur les événements est un monde très différent, et ma tête continue de nager. )

Ai-je vraiment besoin de ces deux?

Non. Le repérage d'itérateurs asynchrones sur une collection est assez simple avec des promesses, mais il nécessite deux étapes au lieu d'un appel de fonction. Tout d'abord, la collection est map à une série de promesses pour l'itération parallèle. Ensuite, ces promesses sont introduites dans Q.all pour faire une promesse pour la collection cartographique. Contrairement à async , l'ordre du résultat est garanti.

 var entries = […]; // some array of objects with "id" attributes var promises = entries.map(function(object) { return asyncPromiseReturingFunction(object); }); // the anonymous wrapper might be omitted return Q.all(promises); 

Pour concat , vous devriez ajouter un

 .then(function(results) { return Array.prototype.concat.apply([], results); });