"Weiter" in cursor.forEach ()

278

Ich erstelle eine App mit meteor.js und MongoDB und habe eine Frage zu cursor.forEach (). Ich möchte zu Beginn jeder Iteration einige Bedingungen überprüfen und dann das Element überspringen, wenn ich die Operation nicht ausführen muss, um Zeit zu sparen.

Hier ist mein Code:

// Fetch all objects in SomeElements collection
var elementsCollection = SomeElements.find();
elementsCollection.forEach(function(element){
  if (element.shouldBeProcessed == false){
    // Here I would like to continue to the next element if this one 
    // doesn't have to be processed
  }else{
    // This part should be avoided if not neccessary
    doSomeLengthyOperation();
  }
});

Ich weiß, dass ich den Cursor mit cursor.find (). Fetch () in ein Array verwandeln und dann die reguläre for-Schleife verwenden kann, um über Elemente zu iterieren und normal fortzufahren und zu brechen, aber ich bin interessiert, ob es etwas Ähnliches gibt, das in forEach (verwendet werden kann) ).

Drag0
quelle

Antworten:

560

Jede Iteration von forEach()ruft die von Ihnen bereitgestellte Funktion auf. Um die weitere Verarbeitung innerhalb einer bestimmten Iteration zu stoppen (und mit dem nächsten Element fortzufahren), müssen Sie nur returndie Funktion an der entsprechenden Stelle verlassen:

elementsCollection.forEach(function(element){
  if (!element.shouldBeProcessed)
    return; // stop processing this iteration

  // This part will be avoided if not neccessary
  doSomeLengthyOperation();
});
nnnnnn
quelle
18
Wissen Sie vielleicht, was die "Pause" sein könnte, wenn Weiter nur "Zurück" ist?
Drag0
5
Ich benutze MongoDB nicht, habe also die Dokumentation nicht gelesen, aber es ist möglich, dass return false;dies dem entspricht break;(wie bei einer jQuery- .each()Schleife). Natürlich kann jeder, der .forEach()
MongoDBs
9
@ Drag0 Sie können .some () als Ersatz für .forEach () verwenden, wodurch Sie false zurückgeben können, um die Schleife zu unterbrechen.
Andrew
6
@ Andrew Sie können verwenden some, aber seien Sie sich bewusst, dass Sie eine Funktion missbrauchen (oder kreativ verwenden), mit der festgestellt werden soll, ob eines der Elemente der Bedingung entspricht. Ein bisschen wie wenn ich sehe, wie Leute mapdas Ergebnis verwenden und ignorieren (sie hätten es verwenden sollen forEach). Es ist Semantik, die Leute müssen zweimal hinschauen, um zu wissen, warum Sie es verwenden, somewenn Sie sich nicht wirklich für das Ergebnis interessieren
Juan Mendes
1
@ Andrew großer Tipp, aber es ist, return truewas die einige Schleife brechen wird
Daviestar
11

Meiner Meinung nach ist dies der beste Ansatz, um dies mithilfe der filter Methode zu erreichen , da es bedeutungslos ist, in einem forEachBlock zurückzukehren. Ein Beispiel für Ihr Snippet:

// Fetch all objects in SomeElements collection
var elementsCollection = SomeElements.find();
elementsCollection
.filter(function(element) {
  return element.shouldBeProcessed;
})
.forEach(function(element){
  doSomeLengthyOperation();
});

Dies wird Ihre eingrenzen elementsCollectionund nur die filtredElemente behalten , die verarbeitet werden sollen.

Ramy Tamer
quelle
3
Dies würde die gefundenen Elemente zweimal wiederholen, einmal in der filterund die zweite in der, forEachwenn es sich um eine große Sammlung handelt, wird es sehr ineffizient sein
Dementic
1
Sie haben Recht, aber ich denke nicht, dass es eine große Sache ist, da die zeitliche Komplexität davon als solche angesehen werden O(2n)kann O(n).
Ramy Tamer
2
Wenn man bedenkt, dass SO von anderen verwendet wird, nicht nur vom OP, verursacht das Posten einer Lösung nur zum Zweck des Posten mehr Schaden als Nutzen. Die obige Antwort macht es in einer Iteration und ist der rightWeg, es zu tun.
Dementic
Beachten Sie, dass die OP-Sammlung kein Array ist, sondern ein Mongo DB-Cursorobjekt, das anscheinend keine .filter()Methode hat. Sie .toArray().filter()
müssten also
7

Hier ist eine Lösung mit for ofund continueanstelle von forEach:


let elementsCollection = SomeElements.find();

for (let el of elementsCollection) {

    // continue will exit out of the current 
    // iteration and continue on to the next
    if (!el.shouldBeProcessed){
        continue;
    }

    doSomeLengthyOperation();

});

Dies kann etwas nützlicher sein, wenn Sie in Ihrer Schleife asynchrone Funktionen verwenden müssen, die in Ihrer Schleife nicht funktionieren forEach. Zum Beispiel:


(async fuction(){

for (let el of elementsCollection) {

    if (!el.shouldBeProcessed){
        continue;
    }

    let res;

    try {
        res = await doSomeLengthyAsyncOperation();
    } catch (err) {
        return Promise.reject(err)
    }

});

})()
jwerre
quelle
2

Verwendung der Kurzschlussauswertung von JavaScripts . Wenn el.shouldBeProcessedtrue zurückgegeben wird,doSomeLengthyOperation

elementsCollection.forEach( el => 
  el.shouldBeProcessed && doSomeLengthyOperation()
);
JSON C11
quelle