Cursor.forEach () öğesinde “devam”


280

Meteor.js ve MongoDB kullanarak bir uygulama geliştiriyorum ve cursor.forEach () hakkında bir sorum var. Her bir yinelemenin başlangıcındaki bazı koşulları kontrol etmek ve daha sonra zaman kazanmak için işlem yapmam gerekmiyorsa öğeyi atlamak istiyorum.

İşte benim 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();
  }
});

Ben imleci cursor.find (). Fetch () kullanarak diziye çevirmek biliyorum ve sonra öğeleri üzerinde yineleme ve devam ve normal kullanım kullanmak için düzenli for-loop kullanın ama forEach (benzer kullanmak için benzer bir şey varsa ilgileniyorum ).

Yanıtlar:


562

Her yineleme, sağladığınız forEach()işlevi çağırır. Herhangi bir yinelemede daha fazla işlemeyi durdurmak (ve bir sonraki öğeye devam etmek) returniçin işlevden uygun noktada yapmanız yeterlidir:

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

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

18
Belki "mola" ne olabilir biliyor musunuz eğer devam sadece "dönüş" ise.
Drag0

5
MongoDB kullanmıyorum, bu yüzden belgelerini okumadım, ancak return false;eşdeğer olması mümkündür break;(jQuery .each()döngüsü için olduğu gibi ). Tabii ki MongoDB'leri uygulayan .forEach()başka fikirler de olabilirdi ...
nnnnnn

9
@ Drag0 Döngüyü kırmak için false döndürmenizi sağlayan .forEach () yerine .some () kullanabilirsiniz.
Andrew

6
@Andrew Kullanabilirsiniz some, sadece herhangi bir öğenin koşulla eşleşip eşleşmediğini söylemek amacıyla bir işlevi kötüye kullandığınızı (veya yaratıcı bir şekilde kullandığınızı) unutmayın. İnsanların mapsonucu kullandığını görüp görmezden geldiğime benzer (kullanmış olmalıydı forEach). Anlambilim, insanlar somesonucu gerçekten umursamadığınızda neden kullandığınızı bilmek için iki kez bakmak zorunda kalacaklar
Juan Mendes

1
@Büyük ipucu verdi, ancak bu return truebazı döngüyü kıracak
daviestar

11

Bence kullanarak bunu başarmak için en iyi yaklaşım olarak filter yöntem , bir de geri dönmek için anlamsız olarak forEachbloğun; snippet'inizdeki bir örnek için:

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

Bu işlem sizi daraltacak elementsCollectionve filtredişlenmesi gereken öğeleri koruyacaktır .


3
Bu, bulunan öğeleri iki kez yineleyecektir, bir kez filterve ikincisi forEachbüyük bir koleksiyonda, çok verimsiz olacaktır
Demans

1
Haklısın, ama bunun zaman karmaşıklığı O(2n)olarak kabul edilebileceği için bunun çok önemli olduğunu düşünmüyorum O(n).
Ramy Tamer

2
SO'nun sadece OP değil, başkaları tarafından kullanıldığını düşünmek, sadece yayınlamak için bir çözüm göndermek, faydadan çok zarar yaratıyor. Yukarıdaki cevap bunu tek bir yinelemede yapar ve rightbunu yapmanın yoludur.
Dementic

OP'nin koleksiyonunun bir dizi olmadığını, bir .filter()yönteme sahip olmadığı bir Mongo DB imleç nesnesi olduğunu unutmayın, bu yüzden yöntemini yapabilmek için .toArray()önce çağırmanız gerekir.filter()
nnnnnn

7

İşte for ofve continueyerine bir çözüm 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();

});

Döngünüzün içinde çalışmayan asenkron işlevler kullanmanız gerekiyorsa, bu biraz daha yararlı olabilir forEach. Örneğin:


(async fuction(){

for (let el of elementsCollection) {

    if (!el.shouldBeProcessed){
        continue;
    }

    let res;

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

});

})()

2

JavaScripts kısa devre değerlendirmesinden yararlanma. Eğer el.shouldBeProcessed, döner gerçekdoSomeLengthyOperation

elementsCollection.forEach( el => 
  el.shouldBeProcessed && doSomeLengthyOperation()
);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.