how to stop Javascript forEach?

JavascriptEcmascript 5

Javascript Problem Overview


I'm playing with Node.js and Mongoose — trying to find specific comment in deep comments nesting with recursive function and forEach within. Is there a way to stop Node.js forEach? As I understand every forEach iteration is a function and and I can't just do break, only return but this won't stop forEach.

function recurs(comment) {
    comment.comments.forEach(function(elem) {

        recurs(elem);

        //if(...) break;

    });
}

Javascript Solutions


Solution 1 - Javascript

You can't break from a forEach. I can think of three ways to fake it, though.

1. The Ugly Way: pass a second argument to forEach to use as context, and store a boolean in there, then use an if. This looks awful.

2. The Controversial Way: surround the whole thing in a try-catch block and throw an exception when you want to break. This looks pretty bad and may affect performance, but can be encapsulated.

3. The Fun Way: use every().

['a', 'b', 'c'].every(function(element, index) {
  // Do your thing, then:
  if (you_want_to_break) return false
  else return true
})

You can use some() instead, if you'd rather return true to break.

Solution 2 - Javascript

Breaking out of https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach">Array#forEach</a> is not possible. (You can inspect the source code that implements it in Firefox on the linked page, to confirm this.)

Instead you should use a normal for loop:

function recurs(comment) {
    for (var i = 0; i < comment.comments.length; ++i) {
        var subComment = comment.comments[i];
        recurs(subComment);
        if (...) {
            break;
        }
    }
}

(or, if you want to be a little more clever about it and comment.comments[i] is always an object:)

function recurs(comment) {
    for (var i = 0, subComment; subComment = comment.comments[i]; ++i) {
        recurs(subComment);
        if (...) {
            break;
        }
    }
}

Solution 3 - Javascript

forEach does not break on return, there are ugly solutions to get this work but I suggest not to use it, instead try to use Array.prototype.some or Array.prototype.every

var ar = [1,2,3,4,5];

ar.some(function(item,index){
  if(item == 3){
     return true;
  }
  console.log("item is :"+item+" index is : "+index);
});

Solution 4 - Javascript

In some cases Array.some will probably fulfil the requirements.

Solution 5 - Javascript

As others have pointed out, you can't cancel a forEach loop, but here's my solution:

ary.forEach(function loop(){
    if(loop.stop){ return; }

    if(condition){ loop.stop = true; }
});

Of course this doesn't actually break the loop, it just prevents code execution on all the elements following the "break"

Solution 6 - Javascript

I guess you want to use Array.prototype.find Find will break itself when it finds your specific value in the array.

var inventory = [
  {name: 'apples', quantity: 2},
  {name: 'bananas', quantity: 0},
  {name: 'cherries', quantity: 5}
];

function findCherries(fruit) { 
  return fruit.name === 'cherries';
}

console.log(inventory.find(findCherries)); 
// { name: 'cherries', quantity: 5 }

Solution 7 - Javascript

You can use Lodash's forEach function if you don't mind using 3rd party libraries.

Example:

var _ = require('lodash');

_.forEach(comments, function (comment) {
    do_something_with(comment);

    if (...) {
        return false;     // Exits the loop.
    }
})

Solution 8 - Javascript

    var f = "how to stop Javascript forEach?".split(' ');
    f.forEach(function (a,b){
        console.info(b+1);
        if (a == 'stop') {
            console.warn("\tposition: \'stop\'["+(b+1)+"] \r\n\tall length: " + (f.length)); 
            f.length = 0; //<--!!!
        }
    });

Solution 9 - Javascript

Array.forEach cannot be broken and using try...catch or hacky methods such as Array.every or Array.some will only make your code harder to understand. There are only two solutions of this problem:

  1. use a old for loop: this will be the most compatible solution but can be very hard to read when used often in large blocks of code:

    var testArray = ['a', 'b', 'c']; for (var key = 0; key < testArray.length; key++) { var value = testArray[key]; console.log(key); // This is the key; console.log(value); // This is the value; }

  2. use the new ECMA6 (2015 specification) in cases where compatibility is not a problem. Note that even in 2016, only a few browsers and IDEs offer good support for this new specification. While this works for iterable objects (e.g. Arrays), if you want to use this on non-iterable objects, you will need to use the Object.entries method. This method is scarcely available as of June 18th 2016 and even Chrome requires a special flag to enable it: chrome://flags/#enable-javascript-harmony. For Arrays, you won't need all this but compatibility remains a problem:

    var testArray = ['a', 'b', 'c']; for (let [key, value] of testArray.entries()) { console.log(key); // This is the key; console.log(value); // This is the value; }

  3. A lot of people would agree that neither the first or second option are good candidates. Until option 2 becomes the new standard, most popular libraries such as AngularJS and jQuery offer their own loop methods which can be superior to anything available in JavaScript. Also for those who are not already using these big libraries and that are looking for lightweight options, solutions like this can be used and will almost be on par with ECMA6 while keeping compatibility with older browsers.

Solution 10 - Javascript

Below code will break the foreach loop once the condition is met, below is the sample example

    var array = [1,2,3,4,5];
    var newArray = array.slice(0,array.length);
    array.forEach(function(item,index){
        //your breaking condition goes here example checking for value 2
        if(item == 2){
            array.length = array.indexOf(item);
        }

    })
    array = newArray;

Solution 11 - Javascript

You can break from a forEach loop if you overwrite the Array method:

(function(){
    window.broken = false;

        Array.prototype.forEach = function(cb, thisArg) {
            var newCb = new Function("with({_break: function(){window.broken = true;}}){("+cb.replace(/break/g, "_break()")+"(arguments[0], arguments[1], arguments[2]));}");
            this.some(function(item, index, array){
                 newCb(item, index, array);
                 return window.broken;
            }, thisArg);
            window.broken = false;
        }
    
}())

example:

[1,2,3].forEach("function(x){\
    if (x == 2) break;\
    console.log(x)\
}")

Unfortunately with this solution you can't use normal break inside your callbacks, you must wrap invalid code in strings and native functions don't work directly (but you can work around that)

Happy breaking!

Solution 12 - Javascript

Wy not use plain return?

function recurs(comment){
comment.comments.forEach(function(elem){
    recurs(elem);
    if(...) return;
});

it will return from 'recurs' function. I use it like this. Althougth this will not break from forEach but from whole function, in this simple example it might work

Solution 13 - Javascript

jQuery provides an each() method, not forEach(). You can break out of each by returning false. forEach() is part of the ECMA-262 standard, and the only way to break out of that that I'm aware of is by throwing an exception.

function recurs(comment) {
  try {
    comment.comments.forEach(function(elem) {
      recurs(elem);
      if (...) throw "done";
    });
  } catch (e) { if (e != "done") throw e; }
}

Ugly, but does the job.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionkulebyashikView Question on Stackoverflow
Solution 1 - JavascriptslezicaView Answer on Stackoverflow
Solution 2 - JavascriptDomenicView Answer on Stackoverflow
Solution 3 - Javascriptimal hasaranga pereraView Answer on Stackoverflow
Solution 4 - JavascriptigorView Answer on Stackoverflow
Solution 5 - JavascriptNoneView Answer on Stackoverflow
Solution 6 - JavascriptShrihari BalasubramaniView Answer on Stackoverflow
Solution 7 - JavascriptexmaxxView Answer on Stackoverflow
Solution 8 - JavascriptВладимирView Answer on Stackoverflow
Solution 9 - JavascriptNicolas BouvretteView Answer on Stackoverflow
Solution 10 - JavascriptD G ANNOJIRAOView Answer on Stackoverflow
Solution 11 - JavascriptApplePearView Answer on Stackoverflow
Solution 12 - JavascriptmorteradView Answer on Stackoverflow
Solution 13 - JavascriptJoe TaylorView Answer on Stackoverflow