Problem
I’m using meteor.js and MongoDB to develop an app, and I have a question concerning cursor.forEach (). I’d like to check some conditions at the start of each forEach loop, then skip the element if I don’t need to do the action on it to save time.
Here is my code:
// 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();
}
});
I’m aware that I could use cursor to change the cursor to an array. find(). I generally use get() and then a conventional for-loop to traverse through elements and utilize continue and break, but I’m curious whether there is something similar in forEach ().
Asked by Drag0
Solution #1
Each repetition of the forEach() function will call the function you provided. To cease further processing (and go on to the next item) inside a given iteration, just return from the function at the appropriate point:
elementsCollection.forEach(function(element){
if (!element.shouldBeProcessed)
return; // stop processing this iteration
// This part will be avoided if not neccessary
doSomeLengthyOperation();
});
Answered by nnnnnn
Solution #2
The simplest way to achieve this, in my opinion, is to use the filter method, as returning in a forEach block is pointless; for example, in your snippet:
// Fetch all objects in SomeElements collection
var elementsCollection = SomeElements.find();
elementsCollection
.filter(function(element) {
return element.shouldBeProcessed;
})
.forEach(function(element){
doSomeLengthyOperation();
});
This will reduce the size of your elementsCollection and only keep the elements that need to be processed.
Answered by Ramy Tamer
Solution #3
Instead of forEach, here’s an alternative that uses for of and continue:
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();
});
If you need to use asynchronous functions inside your loop that don’t work with forEach, this might be a better option. For example:
(async fuction(){
for (let el of elementsCollection) {
if (!el.shouldBeProcessed){
continue;
}
let res;
try {
res = await doSomeLengthyAsyncOperation();
} catch (err) {
return Promise.reject(err)
}
});
})()
Answered by jwerre
Solution #4
Using JavaScript to perform a short-circuit evaluation. DoSomeLongOperation if el.shouldBeProcessed returns true.
elementsCollection.forEach( el =>
el.shouldBeProcessed && doSomeLengthyOperation()
);
Answered by JSON C11
Solution #5
The simple solution is to include a return statement within the for loop. As @nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
elementsCollection.forEach(function(element){
if (!element.shouldBeProcessed)
return; // stop processing this iteration
// This part will be avoided if not neccessary
doSomeLengthyOperation();
});
but if you want a deep answer to that question then just be with me.
Assuming that you don’t know the implementation of forEach loop then take a look at the following implementation of forEach loop which is exactly the one specified in ECMA-262, 5th edition for forEach loop.
Source JavaScript | MDN Array.prototype.forEach()
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
};
}
You don’t need to understand every line of the above code because the while loop is what we’re interested in.
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++;
}
There is a statement callback, as you can see. call(T, KValue, K, O) We’re not interested in the call() method’s arguments here; instead, we’re interested in the callback binding, which is a function that you pass to your forEach loop in javascript. As you can see, the call method simply invokes the object (javascript function) on which it is invoked, with this value and arguments provided separately.
Take a look at Function.prototype if you’re not sure what call is. MDN | Call() – JavaScript
Consider this: if your function, which in this case is a callback, returns at any point, the loop will be updated as usual. The loop doesn’t care if the callback function completed all of the steps or not; if the control has returned to the loop, the loop must complete its task. Every time the loop is updated, the callback is called with a new set of values. As you can see, T, KValue, K, and O change every time the loop updates, thus once you return from your function, i.e., callback, you are just handing control to the loop you were called in.
In a forEach loop, this is how you skip one iteration.
Answered by Ayush
Post is based on https://stackoverflow.com/questions/18452920/continue-in-cursor-foreach