“ ทำต่อ” ในเคอร์เซอร์ forEach ()


280

ฉันกำลังสร้างแอพโดยใช้ meteor.js และ MongoDB และฉันมีคำถามเกี่ยวกับ cursor.forEach () ฉันต้องการตรวจสอบเงื่อนไขบางอย่างในตอนต้นของแต่ละการวนซ้ำแต่ละครั้งแล้วข้ามองค์ประกอบถ้าฉันไม่ต้องทำการดำเนินการกับมันเพื่อที่ฉันจะได้ประหยัดเวลา

นี่คือรหัสของฉัน:

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

ฉันรู้ว่าฉันสามารถเปลี่ยนเคอร์เซอร์เป็นอาเรย์โดยใช้ cursor.find (). fetch () จากนั้นใช้การวนซ้ำแบบปกติเพื่อวนซ้ำองค์ประกอบต่างๆและใช้การดำเนินการต่อและหยุดพักตามปกติ แต่ฉันสนใจ )

คำตอบ:


561

การวนซ้ำของแต่ละครั้งforEach()จะเรียกใช้ฟังก์ชันที่คุณระบุ หากต้องการหยุดการประมวลผลเพิ่มเติมภายในการวนซ้ำใด ๆ ที่กำหนดไว้ (และดำเนินการตามรายการถัดไป) คุณเพียงต้องทำreturnตามฟังก์ชั่น ณ จุดที่เหมาะสม:

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

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

18
คุณรู้หรือไม่บางทีสิ่งที่อาจเป็น "ตัวแบ่ง" จากนั้นหากการดำเนินการต่อเป็นเพียง "ผลตอบแทน"
Drag0

5
ฉันไม่ได้ใช้ MongoDB ดังนั้นจึงไม่ได้อ่านเอกสารของมัน แต่เป็นไปได้ที่return false;จะเทียบเท่าbreak;(เพราะเป็น jQuery .each()loop) แน่นอนใครก็ตามที่นำมาใช้ MongoDB ของ.forEach()อาจจะมีความคิดอื่น ๆ ...
nnnnnn

9
@ Drag0 คุณสามารถใช้. some () แทน. forEach () ซึ่งช่วยให้คุณกลับเท็จเพื่อทำลายวง
Andrew

6
@Andrew คุณสามารถใช้งานได้someโปรดทราบว่าคุณกำลังใช้งานฟังก์ชั่นที่ตั้งใจจะบอกว่าองค์ประกอบใดตรงกับเงื่อนไขหรือไม่ ชนิดเมื่อฉันเห็นคนใช้mapและไม่สนใจผลลัพธ์ (ควรใช้forEach)มันเป็นความหมายคนจะต้องดูสองครั้งเพื่อทราบว่าทำไมคุณใช้someเมื่อคุณไม่สนใจผลจริง
Juan Mendes

1
@ แอนดรูว์เคล็ดลับที่ดี แต่มันreturn trueจะทำลายลูปบ้าง
เดวิสตาร์

11

ในความคิดของฉันวิธีที่ดีที่สุดเพื่อให้บรรลุนี้โดยใช้filter วิธีการที่มันไม่มีความหมายที่จะกลับมาในforEachบล็อก; สำหรับตัวอย่างในตัวอย่างของคุณ:

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

สิ่งนี้จะแคบลงelementsCollectionและเก็บfiltredองค์ประกอบที่ควรประมวลผลไว้


3
สิ่งนี้จะย้ำองค์ประกอบที่พบสองครั้งหนึ่งครั้งfilterและครั้งที่สองforEachถ้ามันเป็นคอลเลกชันขนาดใหญ่มันจะไม่มีประสิทธิภาพมาก
Dementic

1
คุณมีสิทธิ แต่ผมไม่คิดว่ามันเป็นเรื่องใหญ่เป็นความซับซ้อนเวลานี้จะเป็นซึ่งถือได้ว่าเป็นO(2n) O(n)
Ramy Tamer

2
การพิจารณาว่า SO กำลังถูกใช้โดยผู้อื่นไม่ใช่แค่ OP เท่านั้นที่โพสต์โซลูชันเพื่อจุดประสงค์ในการโพสต์เท่านั้นเป็นการสร้างอันตรายมากกว่าดี คำตอบข้างต้นทำได้ในการทำซ้ำครั้งเดียวและเป็นrightวิธีการทำ
Dementic

โปรดทราบว่าคอลเลกชันของ OP ไม่ใช่อาร์เรย์มันเป็นวัตถุเคอร์เซอร์ Mongo DB ซึ่งดูเหมือนจะไม่มี.filter()วิธีการดังนั้นคุณจะต้องเรียก.toArray()ใช้วิธีการก่อนที่จะทำได้.filter()
nnnnnn

7

นี่คือวิธีใช้for ofและcontinueแทน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();

});

สิ่งนี้อาจมีประโยชน์มากกว่านี้เล็กน้อยถ้าคุณต้องการใช้ฟังก์ชั่นแบบอะซิงโครนัสภายในลูปของคุณซึ่งไม่สามารถใช้งานforEachได้ ตัวอย่างเช่น:


(async fuction(){

for (let el of elementsCollection) {

    if (!el.shouldBeProcessed){
        continue;
    }

    let res;

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

});

})()

2

ใช้ประโยชน์จากการประเมินการลัดวงจรของ JavaScript ถ้าel.shouldBeProcessedผลตอบแทนจริงdoSomeLengthyOperation

elementsCollection.forEach( el => 
  el.shouldBeProcessed && doSomeLengthyOperation()
);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.