cursor.forEach()中的“继续”


279

我正在使用meteor.js和MongoDB构建应用程序,但我对cursor.forEach()有疑问。我想在每次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()将光标转换为数组,然后使用常规的for循环对元素进行迭代,并正常使用continue和break,但是我感兴趣的是forEach( )。

Answers:


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()循环)。当然,实施MongoDB的人.forEach()可能还有其他想法……
nnnnnn

9
@ Drag0您可以使用.some()代替.forEach(),这使您可以返回false来打破循环。
安德鲁(Andrew)

6
@Andrew您可以使用some,只要知道您正在滥用(或创造性地使用)旨在告诉任何元素是否符合条件的函数即可。有点像当我看到人们使用map并忽略结果时(他们应该使用forEach)。这是语义。人们some在不真正关心结果的情况下必须三思而后行才能知道您为什么使用它
Juan Mendes

1
@Andrew很棒的提示,但这return true将打破一些循环
daviestar

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)
拉米·塔默

2
考虑到SO正在被其他人(不仅是OP)使用,仅出于发布目的而发布解决方案,弊大于利。上面的答案是一次迭代right即可完成的,并且是实现此目的的方法。
Dementic '17

请注意,OP的集合不是数组,而是一个Mongo DB游标对象,它似乎没有.filter()方法,因此您必须先调用其.toArray()方法.filter()
nnnnnn

7

这是使用for ofcontinue代替的解决方案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返回true,doSomeLengthyOperation

elementsCollection.forEach( el => 
  el.shouldBeProcessed && doSomeLengthyOperation()
);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.