Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with:

Breaking Out Of jQuery's Each() Iteration Method

By Ben Nadel on

In the past, I've talked about the beauty and the power of jQuery's each() method for collection iteration. But, as awesome as it is, I still find myself falling back to for-loop iteration in cases where I might need to break out of a loop, mid-collection. Today, however, at the jQuery Conference 2010, Karl Swedberg totally rocked my world in the way that only Karl knows how - he showed me that jQuery's each() method also provides this mid-iteration break functionality.

 
 
 
 
 
 
 
 
 
 

In a standard Javascript for-loop, you can always break out of a loop by using the break command within the body of the loop execution:

  • // Loop from 1 to 100.
  • for (var i = 0 ; i < 100 ; i++){
  •  
  • // Log the current iteration.
  • console.log( "Iteration", i );
  •  
  • // Break out of the for-loop.
  • break;
  •  
  • }

In this code, we are planning to loop from one to one hundred; however, we are executing the break command in the body of our iteration. As such, when the above code has finished executing, we are left with the following console output:

Iteration 0

As you can see, the loop entered its first iteration, logged one message to the console, and then completely stopped iterating. The break command that we executed not only halted the current iteration (Iteration 0), it also prevented the other 100 iterations from taking place.

As Karl demonstrated at jQCon, the jQuery each() method allows us to achieve this same kind of control flow by returning false from the iteration callback. To demonstrate this, I'm going to use each() to look for a given list item within an unordered list. Once I have found the desired list item, I am going to break out of the each() iteration and log the success:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Breaking Out Of jQuery's Each() Method</title>
  • <script type="text/javascript" src="./jquery-1.4.3.js"></script>
  • </head>
  • <body>
  •  
  • <h1>
  • Breaking Out of jQuery's Each() Method
  • </h1>
  •  
  • <ul id="girls">
  • <li>Jill</li>
  • <li>Sarah</li>
  • <li>Kim</li>
  • <li>Tricia</li>
  • </ul>
  •  
  •  
  • <!--- When the DOM is ready (ie. now), init scripts. --->
  • <script type="text/javascript">
  •  
  • // Get the girls list collection.
  • var girls = $( "#girls" );
  •  
  • // Now, we are going to be searching for Kim; but, we don't
  • // know if we are going to find her, so set the girl to null.
  • var sarah = null;
  •  
  • // Loop over the girls, looking for Sarah.
  • girls.children().each(
  • function( index, girlNode ){
  • // Get the current girl collection.
  • var girl = $( girlNode );
  •  
  • // Log that we are checking this girl.
  • console.log( "Checking... ", girl.text() );
  •  
  • // Check to see if this girl is Sarah.
  • if (girl.text().indexOf( "Sarah" ) >= 0){
  •  
  • // Save a reference to sarah.
  • sarah = girl;
  •  
  • // Now that we have found Sarah, we don't need to
  • // keep searching. Break out of the each() loop
  • // by returning false.
  • return( false );
  •  
  • }
  • }
  • );
  •  
  • // Check to see that we found sarah.
  • if (sarah){
  •  
  • // Log that we found her.
  • console.log(
  • "That ",
  • sarah.text(),
  • "- she's so hot right now."
  • );
  •  
  • }
  •  
  • </script>
  •  
  • </body>
  • </html>

In the above code, I find all the list items in a given list. Then, I loop over them looking for the one whose text contains the phrase, "sarah." Once I find this list item, I am returning false:

  • return( false )

Doing this - returning false - within the each() iteration callback does the same thing that the break command does within a for-loop. As such, running the above code results in the following console output:

Checking... Jill
Checking... Sarah
That Sarah - she's so hot right now.

As you can see, only the first two out of the four possible list items were searched. Once the target phrase was found in the second list item, the each() iteration was halted.

There was a lot of stuff at jQuery Conference 2010 that was, without a doubt, awesome; but, sometimes it's the little things that come out of nowhere and rock your world. Being able to break out of an each()-based iteration was one of those little things. And, according to a few conversations that I had after Karl's talk, I wasn't the only one who had never seen this jQuery functionality before.




Reader Comments

@Brian,

Right? I'm always just surprised when I've been using something for a while and don't realize some really basic functionality exists.

@Steve,

I think the core code actually uses a triple equals for the False comparison, so returning null is not too bad.

I don't know if I'd say my world has been rocked ;) but that's definitely a useful bit that I'm happy to know now. I wonder if other libraries do the same thing.

Also, just remember that while functional iteration is often convenient, it comes at the cost of overhead and performance. See http://www.youtube.com/watch?v=mHtdZgou0qU at 19:53 for the whole spiel, or 23:32 for the important points.

@Justin,

Good point - there is always going to be a trade off of "ease of use" with "performance" any time you add an abstraction layer. The thing I like most about the each() method in general is just that every iteration gets its own variables scope so you don't run into any late-binding issues with variables.

Also, I know you left me a good comment on my composed-controller stuff - was at a conference all weekend; working on catching up on emails :)

I didn't know you could do this in jQuery! A few days ago I learned that Underscore.js (a functional programming library for JavaScript, that compresses to about 3kb and fits nicely alongside jQuery) has a _.each() function and _.breakLoop() function. The _.breakLoop() function uses a JavaScript 1.7 feature to break the loop, when it's available.

http://documentcloud.github.com/underscore/#breakLoop

@Ben,

Cool - I didn't even know that was a feature in the latest Javascript engines. As far as underscore, it was definitely praised at the jQuery Conference this past weekend.

@Ben & Ben: Note that the usage of _.breakLoop() has been removed from Underscore.js since version of 1.1.3 because it isn't in the ECMAScript 5-spec.

Within the documentation it states "We can stop the loop from within the callback function by returning false.". It also has an example of the use in it.

Documentation is great!

Hi there Ben. I just bumped into this article because I was looking for this kind of solution, but I'm still in trouble with my code. This is the story: I am iterating through several <li> contained in several <ul> of course. Now I now how to break out of any <li> iteration but the last <ul> keeps looping endlessly. This is my code:

var x=0,y=0,dummy,dummy2,pos;
$('ul').each(function()
{
$(this).find('li').each(function(){ /* x jumps from carousel to carousel; y jumps items within a carousel */
if($("ul")[x] == undefined)
return false;
dummy = $("ul")[x].children[y].className;
if(dummy.search("focused") != -1)
{
pos = searchStringInArray(textArray,"{");
dummy2 = $("ul")[x].children[y].innerText;
textArray[pos] = dummy2;
x++;
}
else
y++;
});
});

The "return false;" statement happens when all items within all <ul> have been processed but the flow keeps going there. Have a solution? Thanks in advance.