Async: Async ne protège pas contre les modifications du tableau pendant l'exécution de la fonction

Créé le 4 juil. 2014  ·  6Commentaires  ·  Source: caolan/async

Lorsque vous avez un appel asynchrone, par exemple. async.each , et pendant cette exécution, le tableau qui est transmis a des modifications, alors il peut ne jamais se terminer, ou appellera le rappel deux fois.

Exemple:

async = require "async" 
arr = [1, 2, 3]  
async.each arr, ((i, cb) -> console.log "i"; setImmediate(cb)), (err) -> console.log "done" 
arr.push(4)

Cet exemple parcourt les 3 éléments du tableau d'origine et affiche i mais n'appelle jamais le rappel, car dans async.each cela fait :

if (completed >= arr.length) {
  callback(null);
}

Lorsque l'on regarde le code asynchrone, il fait une comparaison avec arr.length qui peut changer... ne serait-il pas préférable de stocker la longueur du tableau d'origine et de faire une comparaison par rapport à cela, en s'assurant que le rappel terminé sera appelé ?

Violon:
http://jsfiddle.net/4ysKX/1/

bug

Commentaire le plus utile

Async a-t-il fini par interdire les modifications de tableau après coup ? J'ai un cas d'utilisation où il serait bien de modifier le tableau d'origine après coup, afin d'itérer sur plus d'éléments qu'initialement.

Tous les 6 commentaires

Vous avez raison, alors ne le modifiez pas. Clonez votre tableau avant de le transmettre à une fonction asynchrone si vous devez le modifier ultérieurement.

@aearly Oui, c'est une mon humble avis , cela devrait être corrigé dans la bibliothèque principale. Cela m'a mordu deux fois maintenant sur deux projets différents.

Il serait difficile de se protéger contre la modification de _any_ array sans cloner l'entrée, par exemple une modification synchrone dans la fonction d'itérateur, mais la protection contre la modification _asynchrone_ non liée à l'itération devrait être simple même sans clone -- vraiment pas en supposant que arr.length restera constant après avoir lancé les tâches asynchrones (en enregistrant la longueur dans une variable avant l'itération).

(Je travaille avec @bradens -- l'un de nous soumettra un PR avec des tests si c'est bienvenu).

Un PR avec des tests serait le bienvenu, mais c'est finalement à @caolan de le fusionner.

L'inconvénient de cette opération est la surcharge supplémentaire de la copie de la baie. Si vous avez un grand tableau ou si vous appelez async.each et autres plusieurs fois, cela sera plus lent et utilisera plus de mémoire.

Je suis d'accord qu'une copie de tableau serait trop lourde. Je suggère que, puisque l'itération initiale du tableau est synchrone, la longueur du tableau d'origine pourrait être enregistrée pour être vérifiée ultérieurement. De cette façon, le nombre d'appels de rappel correspondra au nombre d'appels d'itérateur, même si le tableau est modifié entre-temps. Cela devrait être facile et sans frais généraux pour async.each , mais je n'ai pas encore examiné les autres fonctions. Ce serait bien si toutes les fonctions parallèles avaient un comportement cohérent dans ces cas.

Il s'agit d'un duplicata du #557.

Async a-t-il fini par interdire les modifications de tableau après coup ? J'ai un cas d'utilisation où il serait bien de modifier le tableau d'origine après coup, afin d'itérer sur plus d'éléments qu'initialement.

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