cursor.forEach()中的"continue"

Dra*_*ag0 244 javascript foreach mongodb meteor

我正在使用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();
  }
});
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用cursor.find().fetch()将光标转换为数组,然后使用常规for循环迭代元素并使用continue并正常打破但是我很感兴趣,如果在forEach中有类似的东西( ).

nnn*_*nnn 488

每次迭代都forEach()将调用您提供的函数.要在任何给定的迭代中停止进一步处理(并继续下一个项目),您只需return从适当的点处的函数:

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

  // This part will be avoided if not neccessary
  doSomeLengthyOperation();
});
Run Code Online (Sandbox Code Playgroud)

  • 如果继续只是"回归",你知道可能是什么"休息"吗? (17认同)
  • @ Drag0您可以使用.some()作为.forEach()的替代,这使您可以返回false来打破循环. (9认同)
  • @Andrew你可以使用`some`,只要知道你在滥用(或创造性地使用)一个函数,该函数旨在告诉任何元素是否符合条件.有点像我看到人们使用`map`并忽略结果(他们应该使用`forEach)`.这是语义,当你不关心结果的时候,人们将不得不两次看你知道你为什么使用`some` (6认同)
  • 我没有使用MongoDB所以没有阅读它的文档,但是`return false;`可能相当于`break;`(因为它是jQuery` .each()`循环).当然,无论谁实现了MongoDB的`.forEach()`,都可能有其他想法...... (5认同)
  • @Andrew 很棒的提示,但是它是 `return true` 会打破一些循环 (3认同)

jwe*_*rre 11

这是一个使用for ofandcontinue而不是 的解决方案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();

});
Run Code Online (Sandbox Code Playgroud)

如果您需要在循环中使用异步函数,而这些函数在forEach. 例如:


(async fuction(){

for (let el of elementsCollection) {

    if (!el.shouldBeProcessed){
        continue;
    }

    let res;

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

});

})()
Run Code Online (Sandbox Code Playgroud)


Ram*_*mer 10

在我看来,通过使用该filter 方法实现这一目标的最佳方法是因为在forEach块中返回是没有意义的; 有关您的代码段的示例:

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

这将缩小您的范围,elementsCollection并保留filtred应处理的元素.

  • 考虑到 SO 正在被其他人使用,而不仅仅是 OP,发布解决方案只是为了发布它,弊大于利。上面的答案是在一次迭代中完成的,并且是“正确”的方法。 (4认同)
  • 这将对找到的元素进行两次迭代,一次是在“过滤器”中,一次是在“ forEach”中,如果它是一个大型集合,那么效率将非常低 (2认同)
  • 你是对的,但我认为这没什么大不了的,因为它的时间复杂度是`O(2n)`,可以被认为是`O(n)`。 (2认同)

Ayu*_*ush 5

简单的答案是在循环return内放置一条语句forEach将为您完成工作,如上所述@nnnnnn

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

  // This part will be avoided if not neccessary
  doSomeLengthyOperation();
});
Run Code Online (Sandbox Code Playgroud)

但如果你想得到这个问题的深入答案,那就跟我来吧。

假设您不知道forEach循环的实现,那么请看一下以下forEach循环的实现,它正是 ECMA-262 第 5 版 forforEach循环中指定的循环实现。

Array.prototype.forEach()源代码 - JavaScript | MDN

if (!Array.prototype['forEach']) {

  Array.prototype.forEach = function(callback, thisArg) {

    if (this == null) { throw new TypeError('Array.prototype.forEach called on null or undefined'); }

    var T, k;
    // 1. Let O be the result of calling toObject() passing the
    // |this| value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get() internal
    // method of O with the argument "length".
    // 3. Let len be toUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If isCallable(callback) is false, throw a TypeError exception.
    // See: https://es5.github.com/#x9.11
    if (typeof callback !== "function") { throw new TypeError(callback + ' is not a function'); }

    // 5. If thisArg was supplied, let T be thisArg; else let
    // T be undefined.
    if (arguments.length > 1) { T = thisArg; }

    // 6. Let k be 0
    k = 0;

    // 7. Repeat, while k < len
    while (k < len) {

      var kValue;

      // a. Let Pk be ToString(k).
      //    This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty
      //    internal method of O with argument Pk.
      //    This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal
        // method of O with argument Pk.
        kValue = O[k];

        // ii. Call the Call internal method of callback with T as
        // the this value and argument list containing kValue, k, and O.
        callback.call(T, kValue, k, O);
      }
      // d. Increase k by 1.
      k++;
    }
    // 8. return undefined
  };
}
Run Code Online (Sandbox Code Playgroud)

你真的不需要理解上面代码的每一行,因为我们感兴趣的是循环while

while (k < len) {

      var kValue;

      // a. Let Pk be ToString(k).
      //    This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty
      //    internal method of O with argument Pk.
      //    This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal
        // method of O with argument Pk.
        kValue = O[k];

        // ii. Call the Call internal method of callback with T as
        // the this value and argument list containing kValue, k, and O.
        callback.call(T, kValue, k, O);
      }
      // d. Increase k by 1.
      k++;
    }
Run Code Online (Sandbox Code Playgroud)

如果您注意到,那么这里又出现了一个声明,callback.call(T, KValue, K, O)我们对此处提供给方法的参数不感兴趣call(),但我们真正感兴趣的是您在 javascript 中为循环提供的callback绑定。请参阅该方法只是调用它所调用的对象(javascript 函数),并使用单独提供的值和参数。functionforEachcallthis

如果您不明白 call 是什么,请查看Function.prototype.Call() - JavaScript | MDN

想想看,如果在callback这种情况下您的函数在任何时候返回,循环将像往常一样更新。循环不关心callback函数是否已执行给定的每个步骤,如果控制已返回到循环,则循环必须完成其工作。每次更新循环时,callback都会使用新的值集进行调用,因为您可以看到T, KValue, K, O每次循环更新时都会发生变化,因此,如果您在任何时候从函数返回,即,callback您只需将控制权交给您所在的循环无论您在什么时候从函数返回,如果您想在给定条件下跳过函数内部的某些操作,那么只需将 return 语句放在您想要跳过的那些语句之前即可。

这就是如何跳过循环内的迭代forEach