"Lanjutkan" di cursor.forEach ()


280

Saya membuat aplikasi menggunakan meteor.js dan MongoDB dan saya punya pertanyaan tentang cursor.forEach (). Saya ingin memeriksa beberapa kondisi di awal setiap iterasi forEach dan kemudian melewati elemen jika saya tidak harus melakukan operasi di atasnya sehingga saya dapat menghemat waktu.

Ini kode saya:

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

Saya tahu saya bisa mengubah kursor ke array menggunakan cursor.find (). Fetch () dan kemudian menggunakan for-loop biasa untuk beralih ke elemen dan menggunakan melanjutkan dan merusak secara normal tapi saya tertarik jika ada sesuatu yang mirip untuk digunakan di forEach ( ).

Jawaban:


562

Setiap iterasi forEach()akan memanggil fungsi yang telah Anda berikan. Untuk berhenti memproses lebih lanjut dalam setiap iterasi yang diberikan (dan melanjutkan dengan item berikutnya) Anda hanya perlu returndari fungsi pada titik yang sesuai:

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

  // This part will be avoided if not neccessary
  doSomeLengthyOperation();
});

18
Apakah Anda tahu mungkin apa yang bisa menjadi "istirahat" maka jika melanjutkan hanya "kembali;".
Tarik0

5
Saya tidak menggunakan MongoDB jadi belum membaca dokumentasinya, tapi mungkin saja itu return false;setara dengan break;(seperti untuk .each()loop jQuery ). Tentu saja siapa pun yang menerapkan MongoDB .forEach()mungkin punya ide lain ...
nnnnnn

10
@ Drag0 Anda dapat menggunakan .some () sebagai pengganti .forEach (), yang memungkinkan Anda untuk mengembalikan false untuk memutus loop.
Andrew

6
@Andrew Anda dapat menggunakan some, hanya perlu diketahui bahwa Anda menyalahgunakan (atau secara kreatif menggunakan) fungsi yang dimaksudkan untuk mengetahui apakah ada elemen yang cocok dengan kondisi tersebut. Seperti ketika saya melihat orang menggunakan mapdan mengabaikan hasilnya (mereka seharusnya menggunakannya forEach). Ini semantik, orang harus melihat dua kali untuk mengetahui mengapa Anda menggunakan somesaat Anda tidak terlalu peduli dengan hasilnya
Juan Mendes

1
@Andrew tip yang hebat, namun itu return trueyang akan mematahkan beberapa loop
daviestar

11

Menurut pendapat saya pendekatan terbaik untuk mencapai ini dengan menggunakan filter metode karena tidak ada artinya untuk kembali dalam satu forEachblok; untuk contoh di cuplikan Anda:

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

Ini akan mempersempit Anda elementsCollectiondan hanya menyimpan filtredelemen yang harus diproses.


3
Ini akan mengulangi elemen yang ditemukan dua kali, sekali di filterdan yang kedua di forEachjika itu adalah koleksi besar, itu akan sangat tidak efisien
Dementic

1
Anda benar, tetapi saya tidak berpikir itu masalah besar karena kompleksitas waktu ini O(2n)yang dapat dianggap sebagai O(n).
Ramy Tamer

2
Mempertimbangkan SO sedang digunakan oleh orang lain, bukan hanya OP, memposting solusi hanya untuk tujuan mempostingnya, membuat lebih banyak kerugian daripada kebaikan. Jawaban di atas melakukannya dalam satu iterasi dan merupakan rightcara untuk melakukannya.
Demensik

Perhatikan bahwa koleksi OP bukan array, ini adalah objek kursor Mongo DB, yang sepertinya tidak memiliki .filter()metode, jadi Anda harus memanggil .toArray()metode sebelum bisa.filter()
nnnnnn

7

Ini adalah solusi menggunakan for ofdan continuebukannya 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();

});

Ini mungkin sedikit lebih berguna jika Anda perlu menggunakan fungsi asinkron di dalam loop Anda yang tidak berfungsi di dalam forEach. Sebagai contoh:


(async fuction(){

for (let el of elementsCollection) {

    if (!el.shouldBeProcessed){
        continue;
    }

    let res;

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

});

})()

2

Memanfaatkan evaluasi hubung singkat JavaScripts . Jika el.shouldBeProcessedmengembalikan true,doSomeLengthyOperation

elementsCollection.forEach( el => 
  el.shouldBeProcessed && doSomeLengthyOperation()
);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.