“continue"在cursor.forEach ()

我正在使用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()中使用类似的东西。

288796 次浏览

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

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


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

在我看来,实现这一点的最佳方法是使用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元素。

下面是一个使用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)
}


});


})()

使用JavaScripts 短路求值。如果el.shouldBeProcessed返回true,则doSomeLengthyOperation .

elementsCollection.forEach( el =>
el.shouldBeProcessed && doSomeLengthyOperation()
);

使用继续语句代替return来跳过JS循环中的迭代。

简单的答案是,在forEach循环中放入return语句将为你完成工作,就像@nnnnnn所说的那样,

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


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

但如果你想知道这个问题的深层答案那就来找我吧。

假设你不知道forEach循环的实现,那么看看下面的forEach循环的实现,它正是ECMA-262,第5版中为forEach循环指定的实现。

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
};
}

你真的不需要理解上面代码的每一行,因为我们感兴趣的是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++;
}

如果你注意到这里有一个语句callback.call(T, KValue, K, O),我们对这里给call()方法的参数不感兴趣,但我们真正感兴趣的是callback绑定,它是你在javascript中给forEach循环的function。请参阅call方法仅调用它所调用的对象(javascript函数),并单独提供this值和参数。

如果你不明白调用是什么,那么看看Function.prototype.Call() - JavaScript | MDN

试想一下,如果在任意一点上,你的函数callback(在本例中为返回)在任意一点上,循环将照常更新。循环并不关心callback函数是否执行了赋予它的每一步,如果控件已返回到循环,则循环必须完成它的工作。每次更新循环的callback叫做新设置的值可以看到T, KValue, K, O正在改变每次循环更新,如果在任何时候你从函数返回即callback你只是把控制的循环称为不管你什么时候回来你的功能,如果你想跳过一些操作在你的函数在给定条件下然后把这些语句你想跳过之前返回语句。

这就是在forEach循环中跳过迭代的方法。

如果你在使用经典的for循环,而不想使用continue,你可以在其中使用自执行函数,并使用return来模仿continue行为:

for (let i = 0; i < 10; i++) {
(() => {
if (i > 5) return;
console.log("no.", i)
})();
}


console.log("exited for loop")

输出:

[LOG]: "no.",  0
[LOG]: "no.",  1
[LOG]: "no.",  2
[LOG]: "no.",  3
[LOG]: "no.",  4
[LOG]: "no.",  5
[LOG]: "exited for loop"