457 votes

Comment arrêter Javascript forEach?

Je joue avec Node.js et Mongoose - en essayant de trouver des commentaires spécifiques dans un enchevêtrement de commentaires profonds avec une fonction récursive et forEach à l'intérieur. Existe-t-il un moyen d'arrêter Node.js forEach? Comme je le comprends, chaque itération de forEach est une fonction et je ne peux pas simplement faire un break, seulement un return mais cela ne cessera pas forEach.

function recurs(comment) {
    comment.comments.forEach(function(elem) {

        recurs(elem);

        //if(...) break;

    });
}

1151voto

uʍop ǝpısdn Points 16540

Vous ne pouvez pas sortir d'une forEach. Je peux penser à trois façons de le simuler, cependant.

1. La Mauvaise Façon : passez un deuxième argument à forEach pour utiliser comme contexte, et stockez un booléen là-dedans, puis utilisez un if. Cela a l'air affreux.

2. La Façon Controversée : entourez le tout d'un bloc try-catch et lancez une exception lorsque vous voulez sortir. Cela a l'air assez moche et peut affecter les performances, mais peut être encapsulé.

3. La Façon Amusante : utilisez every().

['a', 'b', 'c'].every(function(element, index) {
  // Faites votre truc, puis :
  if (you_want_to_break) return false
  else return true
})

Vous pouvez utiliser some() à la place, si vous préférez return true pour sortir.

81 votes

+1, bien que cela me semble plus naturel d'utiliser some() et return true lorsque vous voulez sortir.

30 votes

Ou de manière plus élégante, placez return !you_want_to_break à l'intérieur de la boucle au lieu du bloc if..else. Économise deux lignes. :-)

24 votes

every pris en charge partout sauf IE7 & 8 (j'ai dû chercher, donc j'ai pensé que je partagerais)

67voto

Domenic Points 40761

Il n'est pas possible de sortir de Array#forEach. (Vous pouvez inspecter le code source qui l'implémente dans Firefox sur la page liée, pour le confirmer.)

Vous devriez plutôt utiliser une simple boucle for:

function recurs(comment) {
    for (var i = 0; i < comment.comments.length; ++i) {
        var subComment = comment.comments[i];
        recurs(subComment);
        if (...) {
            break;
        }
    }
}

(ou, si vous voulez être un peu plus astucieux et que comment.comments[i] est toujours un objet:)

function recurs(comment) {
    for (var i = 0, subComment; subComment = comment.comments[i]; ++i) {
        recurs(subComment);
        if (...) {
            break;
        }
    }
}

0 votes

Il est possible en jetant à l'intérieur de la fonction forEach, comme le dit la réponse acceptée.

5 votes

C'est sûr, mais utiliser des exceptions pour contrôler le flux du programme est une très mauvaise pratique

39voto

igor Points 642

Dans certains cas, Array.some remplira probablement les exigences.

0 votes

Cela devrait être la réponse canonique car elle arrêtera en fait le traitement une fois qu'elle trouve le bon élément. Alors que forEach et every (tel que je le comprends) peuvent être piratés pour renvoyer true sur le premier élément trouvé, il parcourra quand même l'ensemble du tableau. Deuxièmement, Javascript ne réalise pas d'optimisation de queue et donc toutes les fonctions récursives sont intrinsèquement fragiles jusqu'à ce que ES6 sorte.

1 votes

Comment est le support du navigateur ?

0 votes

@imalhasarangaperera Ici, vous pouvez trouver le support actuel du navigateur. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

31voto

zyklus Points 31683

Comme d'autres l'ont souligné, vous ne pouvez pas annuler une boucle forEach, mais voici ma solution :

ary.forEach(function loop(){
    if(loop.stop){ return; }

    if(condition){ loop.stop = true; }
});

Bien entendu, cela ne casse pas vraiment la boucle, cela empêche simplement l'exécution du code sur tous les éléments suivant le "break"

1 votes

J'aime celui-ci. Je combinerais simplement la dernière ligne à loop.stop = condition cependant. Cela ne devrait pas faire de différence car lorsqu'il est défini sur true il ne sera plus exécuté.

2 votes

Usage astucieux des expressions de fonction nommées

15 votes

Je ne pense pas que cette solution soit une bonne idée. Imaginez que vous parcourez 10000 éléments et que votre condition est de vous arrêter au deuxième élément, vous allez donc effectuer une itération inutile de 9998 fois pour rien. Les meilleures approches sont soit d'utiliser some ou every.

-11voto

user2381380 Points 1

Pourquoi ne pas utiliser simplement le retour?

function recurs(comment){
comment.comments.forEach(function(elem){
    recurs(elem);
    if(...) return;
});

cela retournera de la fonction 'recurs'. Je l'utilise de cette façon. Bien que cela ne rompra pas la boucle forEach mais de la fonction entière, dans cet exemple simple cela pourrait fonctionner

0 votes

Vous ne pouvez pas revenir dans une boucle

1 votes

@Hazaart Bien que vous ne puissiez pas le faire dans forEach, vous pouvez retourner dans les boucles et la fonction sortira sans aucune autre itération de la boucle. (par ex. for (... in ...), while, etc.)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X