„Kontynuuj” w kursor.forEach ()

279

Tworzę aplikację za pomocą Mete.js i MongoDB i mam pytanie dotyczące kursora.forEach (). Chcę sprawdzić niektóre warunki na początku każdej iteracji forEach, a następnie pominąć element, jeśli nie muszę wykonywać na nim operacji, aby zaoszczędzić trochę czasu.

Oto mój kod:

// 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();
  }
});

Wiem, że mogłem zamienić kursor na tablicę za pomocą kursora.find (). Fetch (), a następnie użyć zwykłej pętli for do iteracji elementów oraz użyć kontynuacji i przerwania normalnie, ale jestem zainteresowany, jeśli jest coś podobnego do użycia w forEach ( ).

Przeciągnij0
źródło

Odpowiedzi:

561

Każda iteracja forEach()wywoła podaną przez ciebie funkcję. Aby zatrzymać dalsze przetwarzanie w ramach dowolnej iteracji (i przejść do następnego elementu), musisz po prostu returnz funkcji w odpowiednim punkcie:

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

  // This part will be avoided if not neccessary
  doSomeLengthyOperation();
});
nnnnnn
źródło
18
Czy wiesz może, co może być „przełamaniem”, to jeśli kontynuacja to po prostu „powrót;”.
Drag0,
5
Nie używam MongoDB, więc nie przeczytałem jego dokumentacji, ale możliwe, że return false;będzie to odpowiednik break;(tak jak w przypadku .each()pętli jQuery ). Oczywiście, ktokolwiek wdrożył MongoDB, .forEach()mógł mieć inne pomysły ...
nnnnnn
9
@ Drag0 Możesz użyć .some () jako zamiennika dla .forEach (), która umożliwia zwrócenie wartości false w celu przerwania pętli.
Andrew,
6
@Andrew Możesz użyć some, pamiętaj jednak, że niewłaściwie używasz (lub twórczo używasz) funkcji, która miała na celu stwierdzenie, czy któryś z elementów spełnia ten warunek. Coś w stylu, gdy widzę, że ludzie używają mapi ignorują wynik (powinni byli użyć forEach). To semantyka, ludzie będą musieli dwa razy spojrzeć, aby dowiedzieć się, dlaczego używasz, somegdy tak naprawdę nie zależy ci na wyniku
Juan Mendes,
1
@Andrew świetna wskazówka, ale to return trueprzerwie jakąś pętlę
daviestar
11

Moim zdaniem najlepsze podejście do osiągnięcia tego celu filter polega na zastosowaniu metody, ponieważ powrót do forEachbloku nie ma sensu ; na przykład we fragmencie:

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

Spowoduje to zawężenie twojego elementsCollectioni zachowanie filtredelementów, które powinny być przetworzone.

Ramy Tamer
źródło
3
Spowodowałoby to powtórzenie znalezionych elementów dwa razy, raz w, filtera drugi w forEachdużej kolekcji, byłoby bardzo nieefektywne
Dementic
1
Masz rację, ale nie sądzę, żeby to była wielka sprawa, ponieważ złożoność czasowa tego O(2n)może być uważana za O(n).
Ramy Tamer
2
Biorąc pod uwagę, że SO jest używany przez innych, nie tylko OP, opublikowanie rozwiązania tylko w celu opublikowania go, powoduje więcej szkody niż pożytku. Powyższa odpowiedź robi to w jednej iteracji i jest na to rightsposób.
Dementyczny
Zauważ, że kolekcja OP nie jest tablicą, to obiekt kursora Mongo DB, który nie wydaje się mieć .filter()metody, więc musisz wywołać jej .toArray()metodę, zanim będziesz mógł.filter()
nnnnnn
7

Oto rozwiązanie wykorzystujące for ofi continuezamiast 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();

});

Może to być nieco bardziej przydatne, jeśli chcesz użyć funkcji asynchronicznych w pętli, które nie działają w środku forEach. Na przykład:


(async fuction(){

for (let el of elementsCollection) {

    if (!el.shouldBeProcessed){
        continue;
    }

    let res;

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

});

})()
Jwerre
źródło
2

Wykorzystanie oceny zwarć JavaScript . Jeśli el.shouldBeProcessedzwraca true,doSomeLengthyOperation

elementsCollection.forEach( el => 
  el.shouldBeProcessed && doSomeLengthyOperation()
);
JSON C11
źródło