Breaking Out Of jQuery's Each() Iteration Method

Posted October 18, 2010 at 9:31 AM by Ben Nadel

Tags: Javascript / DHTML

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

Oct 18, 2010 at 12:11 PM // reply »
39 Comments

That should simplify my code somewhat. I don't know how many times I've used that same "break" method you mentioned at the top...


Oct 18, 2010 at 12:51 PM // reply »
70 Comments

And a simple "return" is the equivalent of "continue".


Oct 18, 2010 at 12:58 PM // reply »
70 Comments

After reading this article, I'm thinkin' maybe I should switch to using "return true" for "continue". Returning nothing is kinda falsy.


Oct 18, 2010 at 11:24 PM // reply »
10,743 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.


Oct 19, 2010 at 4:21 AM // reply »
3 Comments

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.


Oct 19, 2010 at 8:08 AM // reply »
10,743 Comments

@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 :)


Oct 19, 2010 at 10:05 AM // reply »
8 Comments

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


Oct 19, 2010 at 6:18 PM // reply »
10,743 Comments

@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.


Oct 20, 2010 at 9:37 AM // reply »
1 Comments

Hey! Sarah isn't all that. She may have the figure, but I have the boobs!


Oct 20, 2010 at 9:39 AM // reply »
10,743 Comments

@Jill,

Ha ha ha :)


Feb 21, 2011 at 4:20 PM // reply »
1 Comments

It worked !!

Thanks


Apr 25, 2012 at 5:24 AM // reply »
1 Comments

@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.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 16, 2012 at 8:18 PM
Best Of ColdFusion 10 Contest Entry - HTML Email Utility
Just found this, looks good! I'm trying to run it on local, it's the 64bit version and I'm experiencing horrible lag. On average the generate.cfm processes the content change in 60-90 seconds. I've ... read »
May 16, 2012 at 6:40 PM
Maintaining Sessions Across Multiple ColdFusion CFHttp Requests
I am trying to integrate this CFHTTPsession into an application that will log into zeekrewards.com to post ads and I am not having any luck. The code works perfectly for logging into other websites, ... read »
May 16, 2012 at 2:44 PM
Creating A Sometimes-Fixed-Position Element With jQuery
Thank you, very useful technique! Worked like a charm. ... read »
May 16, 2012 at 1:58 PM
Movies As A Religious Experience
Acting can, in a way, ruin the movie-goer's experience. I used to be able to get so caught up in movies and their plots, and totally engaged. But lately, I haven't been able to as much with a lot o ... read »
May 16, 2012 at 1:52 PM
The Science Of Optimal Post-Exercise Nutrition
children of this age eat very less vegetables so u can opt for salads they will like it also carrot ,cucumber,onion and as far as pulses are concerned u can boil them ,give him along with mashed rice ... read »
May 16, 2012 at 1:34 PM
Strange ColdFusion JRUN Stack Overflow Error
Hey, Recently I updated my jrun4 using the latest updater 7 and now i am having memory issues :(:(:( any help is appreciated ... read »
May 16, 2012 at 9:56 AM
ColdFusion 10 Beta, Apache Tomcat, And Symbolic Links On Mac OSX
Hi, Now that ColdFusion 10 is out I have stumbled over this as well and I cannot figure out the proper solution. We're running virtual hosts via Apache2; the ColdFusion-applications store their fil ... read »
May 15, 2012 at 6:03 PM
Movies As A Religious Experience
@Ben, I don't know whether you'd consider this a religious observation, but it seems to me, in a sense, movies multiply how many lives we get to have. Each movie is like a little extra life we get ... read »