I'm looking for a way to stop iterations of underscore.js _.each()
method, but can't find the solution. jQuery .each()
can break if you do return false
.
Is there a way to stop underscore each()?
_([1,2,3]).each(function(v){
if (v==2) return /*what?*/;
})
forEach
function does not offer this feature either.
each
with a closure (in most languages), you want to filter your list first. That way you don't have to worry about breaking from it. Generally speaking, if you need to break early from an iteration, there's probably a different way that you could be doing it.
each
closure) is similar to JavaScript.
Array.every
to emulate the behavior you want.
You can't break from the each
method—it emulates the native forEach
method's behavior, and the native forEach
doesn't provide to escape the loop (other than throwing an exception).
However, all hope is not lost! You can use the Array.every
method. :)
From that link:
every executes the provided callback function once for each element present in the array until it finds one where callback returns a false value. If such an element is found, the every method immediately returns false.
In other words, you could do something convoluted like this (link to JSFiddle):
[1, 2, 3, 4].every(function(n) {
alert(n);
return n !== 3;
});
This will alert 1
through 3
, and then "break" out of the loop.
You're using underscore.js, so you'll be pleased to learn that it does provide an every
method—they call it every
, but as that link mentions, they also provide an alias called all
.
Update:
_.find would be better as it breaks out of the loop when the element is found:
var searchArr = [{id:1,text:"foo"},{id:2,text:"bar"}];
var count = 0;
var filteredEl = _.find(searchArr,function(arrEl){
count = count +1;
if(arrEl.id === 1 ){
return arrEl;
}
});
console.log(filteredEl);
//since we are searching the first element in the array, the count will be one
console.log(count);
//output: filteredEl : {id:1,text:"foo"} , count: 1
** Old **
If you want to conditionally break out of a loop, use _.filter api instead of _.each. Here is a code snippet
var searchArr = [{id:1,text:"foo"},{id:2,text:"bar"}];
var filteredEl = _.filter(searchArr,function(arrEl){
if(arrEl.id === 1 ){
return arrEl;
}
});
console.log(filteredEl);
//output: {id:1,text:"foo"}
_.find
does exactly what is asked : iterate over the list until the callback returns true
.
You can have a look to _.some
instead of _.each
. _.some
stops traversing the list once a predicate is true. Result(s) can be stored in an external variable.
_.some([1, 2, 3], function(v) {
if (v == 2) return true;
})
See http://underscorejs.org/#some
_([1,2,3]).find(function(v){
return v if (v==2);
})
Maybe you want Underscore's any() or find(), which will stop processing when a condition is met.
Like the other answers, it's impossible. Here is the comment about breaker in underscore underscore issue #21
You cannot break a forEach
in underscore, as it emulates EcmaScript 5 native behaviour.
I believe if your array was actually an object you could return using an empty object.
_.({1,2,3,4,5}).each(function(v){
if(v===3) return {};
});
It's also good to note that an each loop cannot be broken out of — to break, use _.find instead.
Update:
You can actually "break" by throwing an error inside and catching it outside: something like this:
try{
_([1,2,3]).each(function(v){
if (v==2) throw new Error('break');
});
}catch(e){
if(e.message === 'break'){
//break successful
}
}
This obviously has some implications regarding any other exceptions that your code trigger in the loop, so use with caution!
worked in my case
var arr2 = _.filter(arr, function(item){
if ( item == 3 ) return item;
});
Success story sharing
_.every()
nor a_.all()
method for arrays in underscore - so stick to theArray.every()
.every
. So watch out for readability._.each()
has a note specifically about the fact that you can't break out of the loop, and recommend that you use_.find()
instead. http://underscorejs.org/#each