Async: Moyen de déterminer les éléments non traités à partir de async.map() après l'émission d'une erreur

Créé le 10 juil. 2017  ·  5Commentaires  ·  Source: caolan/async

Salut,

Lors de l'utilisation de map(...), existe-t-il un moyen lors de la gestion d'une erreur émise par la fonction iteratee de déterminer combien d'éléments n'ont pas encore été traités à partir de la collection fournie ?

J'utilise map pour effectuer plusieurs requêtes HTTP sortantes (à l'aide de la bibliothèque de nœuds request ) pour un tableau de différents urlsparams, etc. À mi-chemin de l'une de ces requêtes, je peux obtenir une erreur particulière du serveur cible que je peux gérer, mais je veux ensuite retraiter l'élément en cours de travail, puis tous ceux qui restent que map n'a pas encore récupérés.

Je me suis interrogé sur la possibilité de définir un indicateur sur chaque élément de ma collection qui a été travaillé avec succès (sans erreur), puis lorsque l'erreur qui m'intéresse est émise, traitez-la en conséquence. Ensuite, créez peut-être un nouveau tableau à partir des éléments avec l'indicateur défini sur false pour ceux qui ne sont pas encore traités et effectuez un autre map sur ceux-ci, en vous assurant d'invoquer le rappel final d'origine à partir de la carte d'origine.

Je ne sais pas si cela a un sens, mais existe-t-il un moyen d'atteindre ce que j'ai décrit ci-dessus ?

question

Commentaire le plus utile

Salut @parky128 , merci pour la question !

Envelopper le iteratee avec reflect fonctionnerait-il ? reflect passe toujours un objet de résultat au callback , donc même si l'une des erreurs de fonctions iteratee , map se terminerait. Ensuite, vous pouvez simplement itérer sur l'objet results partir de map , vérifier lesquels ont une propriété error , puis le gérer en conséquence. Vous n'auriez pas à retraiter les articles que map n'auraient peut-être pas ramassés.

async.map(coll, async.reflect(function(val, callback) {
  // your request code
}, function(err, results) {
  // err will always be null now
  results.forEach(function(result, i) {
    if (result.error) {
      // your code for handling errors
      // if `coll` is an array, you could access the value that caused 
      // this error through `coll[i]` as `map` preserves the order for arrays 
    } else {
      // otherwise `result.value` will contain the result of that `iteratee` call
    }
  });
});

Sinon, pour répondre à votre question, map renvoie toujours un array . Vous pouvez parcourir ce tableau et vérifier quelles valeurs sont undefined . Ceux-ci correspondront au(x) élément(s) en erreur, passés undefined à leur callback , étaient en cours lorsque le error s'est produit ou n'avait pas démarré. L'approche reflect est probablement l'option la plus sûre, car undefined peut être un résultat valide d'un appel iteratee .

Tous les 5 commentaires

Salut @parky128 , merci pour la question !

Envelopper le iteratee avec reflect fonctionnerait-il ? reflect passe toujours un objet de résultat au callback , donc même si l'une des erreurs de fonctions iteratee , map se terminerait. Ensuite, vous pouvez simplement itérer sur l'objet results partir de map , vérifier lesquels ont une propriété error , puis le gérer en conséquence. Vous n'auriez pas à retraiter les articles que map n'auraient peut-être pas ramassés.

async.map(coll, async.reflect(function(val, callback) {
  // your request code
}, function(err, results) {
  // err will always be null now
  results.forEach(function(result, i) {
    if (result.error) {
      // your code for handling errors
      // if `coll` is an array, you could access the value that caused 
      // this error through `coll[i]` as `map` preserves the order for arrays 
    } else {
      // otherwise `result.value` will contain the result of that `iteratee` call
    }
  });
});

Sinon, pour répondre à votre question, map renvoie toujours un array . Vous pouvez parcourir ce tableau et vérifier quelles valeurs sont undefined . Ceux-ci correspondront au(x) élément(s) en erreur, passés undefined à leur callback , étaient en cours lorsque le error s'est produit ou n'avait pas démarré. L'approche reflect est probablement l'option la plus sûre, car undefined peut être un résultat valide d'un appel iteratee .

Merci d'avoir pris le temps de proposer une solution potentielle. Je voudrais en fait que le rappel final async.map soit invoqué dès que l'une des erreurs de fonctions iteratee avec le cas d'erreur particulier que je cherche à détecter.

En regardant les documents que je vois, je peux y parvenir en transmettant une erreur à la fonction de rappel iteratee, mais je me demande si, dans le rappel final, async.map invoquera, si je pourrais simplement utiliser cet objet de résultats pour comparer avec l'original collecte et voir ce qu'il reste à traiter.

Je ne veux tout simplement pas qu'async.map tente de traiter d'autres demandes dès que l'une d'entre elles renvoie le cas d'erreur qui m'intéresse.

Je ne veux tout simplement pas qu'async.map tente de traiter d'autres demandes dès que l'une d'entre elles renvoie le cas d'erreur qui m'intéresse.

En supposant que votre iteratee soit asynchrone, async.map aura commencé à traiter tous les éléments lorsque le rappel final sera invoqué. Vous pouvez potentiellement comparer l'objet de résultats à la collection pour voir quels éléments n'ont pas encore terminé le traitement, mais cela a aussi ses pièges. Par exemple, vous devrez le faire de manière synchrone, sur la même coche, le rappel final est appelé, car l'objet de résultats sera mis à jour en tant que résolution de iteratee .

Vous pouvez essayer mapSeries . mapSeries n'exécutera qu'une seule requête à la fois. c'est-à-dire qu'il n'appelle l'élément suivant que lorsque le traitement en cours est terminé (au lieu de les démarrer tous en même temps). Cela signifie qu'en cas d'erreur et que le rappel final est invoqué, plus aucun iteratee ne sera exécuté. Vous pouvez ensuite comparer les résultats à la collection pour voir quels éléments n'ont pas encore été traités. C'est encore un peu une solution de contournement, mais c'est plus agréable que d'utiliser async.map . Le principal inconvénient de cette approche est cependant que les demandes ne sont plus traitées en parallèle.

Par exemple, si votre collection est un tableau

async.mapSeries(coll, function(val, callback) {
  // your iteratee function
}, function(err, results) {
  if (err) {
    // unprocessItems will include the item that errored.
    var unprocessItems = coll.slice(results.length - 1);
    // handle the unprocessedItems
  }
});

Hmm Ok, oui ma fonction iteratee est asynchrone car elle utilise la bibliothèque de requêtes pour faire une requête http sortante et je la rappelle avec le résultat. Donc, si je dis qu'il y avait 10 éléments sur lesquels itérer, 4 ont réussi et le 5ème a échoué, ce que j'appellerais ensuite le rappel de la fonction iteratee avec un paramètre d'erreur, si cela signifie que l'objet de résultats dans le rappel final à async.map ne contiendra que les 4 bons résultats ?

Si c'est le cas, pour l'instant, je vivrai avec le fait qu'il fera toujours tous les appels sortants. Je peux en fin de compte être un moi pour diviser mon tableau en tableaux plus petits et effectuer des cartes async.

@hargasinski - J'ai fini par utiliser l'approche async.reflect et cela fonctionne bien pour moi, me donne une visibilité complète de tous les éléments qui ont donné une erreur :+1:

Merci!

Cette page vous a été utile?
0 / 5 - 0 notes