390 Stimmen

"weiter" in cursor.forEach()

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

Hier ist mein Code:

// Alle Objekte in der SomeElements Sammlung abrufen
var elementsCollection = SomeElements.find();
elementsCollection.forEach(function(element){
  if (element.shouldBeProcessed == false){
    // Hier würde ich gerne zum nächsten Element weitergehen, wenn dieses nicht bearbeitet werden muss
  }else{
    // Dieser Teil sollte vermieden werden, wenn nicht notwendig
    doSomeLengthyOperation();
  }
});

Ich weiß, dass ich den Cursor in ein Array umwandeln und dann eine normale for-Schleife verwenden könnte, um über die Elemente zu iterieren und continue und break normal zu verwenden, aber ich interessiere mich dafür, ob es etwas Ähnliches gibt, das in forEach() verwendet werden kann.

733voto

nnnnnn Punkte 142888

Jede Iteration des 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 einfach return aus der Funktion an der entsprechenden Stelle verwenden:

elementsCollection.forEach(function(element){
  if (!element.shouldBeProcessed)
    return; // Verarbeitung dieser Iteration stoppen

  // Dieser Teil wird vermieden, wenn nicht notwendig
  doSomeLengthyOperation();
});

17voto

Ramy Tamer Punkte 618

In meiner Meinung nach ist der beste Ansatz, dies zu erreichen, die Verwendung der filter Methode, da es sinnlos ist, dies in einem forEach Block zurückzugeben; für ein Beispiel in Ihrem Code:

// Holen Sie alle Objekte in der SomeElements-Sammlung
var elementsCollection = SomeElements.find();
elementsCollection
.filter(function(element) {
  return element.shouldBeProcessed;
})
.forEach(function(element){
  doSomeLengthyOperation();
});

Dies wird Ihre elementsCollection eingrenzen und nur die gefilterten Elemente behalten, die verarbeitet werden sollen.

11voto

jwerre Punkte 8488

Hier ist eine Lösung, die for of und continue anstelle von forEach verwendet:

let elementsCollection = SomeElements.find();

for (let el of elementsCollection) {

    // continue wird die aktuelle Iteration beenden 
    // und mit der nächsten fortfahren
    if (!el.shouldBeProcessed){
        continue;
    }

    doSomeLengthyOperation();

});

Dies kann nützlicher sein, wenn Sie asynchrone Funktionen in Ihrer Schleife verwenden möchten, die nicht innerhalb von forEach funktionieren. 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)
    }

});

})()

5voto

Ayush Punkte 366

Die einfache Antwort ist, eine return-Anweisung innerhalb der forEach-Schleife setzen, wie es @nnnnnn gesagt hat,

elementsCollection.forEach(function(element){
  if (!element.shouldBeProcessed)
    return; // Verarbeitung dieser Iteration abbrechen

  // Dieser Teil wird vermieden, wenn nicht notwendig
  doSomeLengthyOperation();
});

aber wenn du eine ausführliche Antwort auf diese Frage möchtest, dann bleib bei mir.

Annehmen, dass du die Implementierung der forEach-Schleife nicht kennst, dann sieh dir die folgende Implementierung der forEach-Schleife an, die genau diejenige ist, die in ECMA-262, 5. Edition für die forEach-Schleife spezifiziert ist.

Quelle Array.prototype.forEach() - JavaScript | MDN

if (!Array.prototype['forEach']) {

  Array.prototype.forEach = function(callback, thisArg) {

    if (this == null) { throw new TypeError('Array.prototype.forEach called on null or undefined'); }

    var T, k;
    // 1. Lasse O das Ergebnis des Aufrufs von toObject() unter Verwendung des
    // |this| Werts als Argument sein.
    var O = Object(this);

    // 2. Lasse lenValue das Ergebnis des Aufrufs der Get() internen
    // Methode von O mit dem Argument "length" sein.
    // 3. Lasse len toUint32(lenValue) sein.
    var len = O.length >>> 0;

    // 4. Wenn isCallable(callback) false ist, wirf eine TypeError Ausnahme.
    // Siehe: https://es5.github.com/#x9.11
    if (typeof callback !== "function") { throw new TypeError(callback + ' is not a function'); }

    // 5. Wenn thisArg übergeben wurde, lass T thisArg sein; andernfalls lass
    // T undefined sein.
    if (arguments.length > 1) { T = thisArg; }

    // 6. Lass k 0 sein.
    k = 0;

    // 7. Wiederhole, solange k < len
    while (k < len) {

      var kValue;

      // a. Lass Pk zu ToString(k) sein.
      //    Das ist implizit für LHS Operanden des in Operators
      // b. Lass kPresent das Ergebnis des Aufrufs der HasProperty
      // internen Methode von O mit Argument Pk sein.
      // Dieser Schritt kann mit c kombiniert werden.
      // c. Wenn kPresent true ist, dann
      if (k in O) {

        // i. Lass kValue das Ergebnis des Aufrufs der Get internen
        // Methode von O mit dem Argument Pk sein.
        kValue = O[k];

        // ii. Ruf die Call interne Methode von callback mit T als
        // dem this Wert und Argumentenliste, die kValue, k und O enthalten, auf.
        callback.call(T, kValue, k, O);
      }
      // d. Erhöhe k um 1.
      k++;
    }
    // 8. Gib undefined zurück
  };
}

Es ist wirklich nicht notwendig, jede Zeile des obigen Codes zu verstehen, denn was uns interessiert, ist die while-Schleife,

while (k < len) {

      var kValue;

      // a. Lass Pk zu ToString(k) sein.
      //    Das ist implizit für LHS Operanden des in Operators
      // b. Lass kPresent das Ergebnis des Aufrufs der HasProperty
      // internen Methode von O mit Argument Pk sein.
      // Dieser Schritt kann mit c kombiniert werden.
      // c. Wenn kPresent true ist, dann
      if (k in O) {

        // i. Lass kValue das Ergebnis des Aufrufs der Get internen
        // Methode von O mit dem Argument Pk sein.
        kValue = O[k];

        // ii. Ruf die Call interne Methode von callback mit T als
        // dem this Wert und Argumentenliste, die kValue, k und O enthalten, auf.
        callback.call(T, kValue, k, O);
      }
      // d. Erhöhe k um 1.
      k++;
    }

Wenn du bemerkst, gibt es eine Anweisung callback.call(T, KValue, K, O) wieder sind wir nicht an den Argumenten interessiert, die dem call()-Methode hier übergeben werden, sondern woran wir wirklich interessiert sind, ist die Bindung des callback, die eine function ist, die du deiner forEach-Schleife in JavaScript gibst. Sieh dir die Methode call einfach ruft das Objekt (JavaScript-Funktion) auf, auf das sie aufgerufen wird, mit einem this-Wert und individuell bereitgestellten Argumenten auf.

Wenn du nicht verstehst, was call ist, dann sieh dir Function.prototype.Call() - JavaScript | MDN an.

Du musst dir nur überlegen, wenn deine Funktion, die callback in diesem Fall zurückgibt, zu einem beliebigen Zeitpunkt wird die Schleife wie gewohnt aktualisiert. Die Schleife kümmert sich nicht darum, ob die callback-Funktion jeden einzelnen Schritt ausgeführt hat, der ihr gegeben wurde; wenn die Kontrolle zur Schleife zurückgegeben wurde, muss die Schleife ihre Aufgabe erfüllen. Jedes Mal, wenn die Schleife aktualisiert wird, wird der callback mit einem neuen Satz von Werten aufgerufen, wie du dort siehst T, KValue, K, O ändern sich jedes Mal, wenn sich die Schleife aktualisiert, also wenn du an einem Punkt aus deiner Funktion zurückkehrst, d. h. callback, gibst du einfach die Kontrolle an die Schleife weiter, in der du aufgerufen wurdest, egal an welchem Punkt du aus deiner Funktion zurückkehrst, wenn du einige Operationen in deiner Funktion zu einer gegebenen Bedingung überspringen möchtest, dann setze die return-Anweisung einfach vor die Anweisungen, die du überspringen möchtest.

So überspringst du eine Iteration innerhalb einer forEach-Schleife.

3voto

JSON C11 Punkte 9927

Verwendung der kurzschlusswertung von JavaScript. Wenn el.shouldBeProcessed true zurückgibt, wird doSomeLengthyOperation ausgeführt.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X