Skip to main content

Bug Tracker

Side navigation

#3776 closed bug (invalid)

Opened January 04, 2009 05:51AM UTC

Closed January 11, 2009 03:57AM UTC

$.each iterator extremely inefficient with arrays with no values at lower index positions

Reported by: mmikeyy Owned by:
Priority: major Milestone: 1.3
Component: core Version: 1.2.6
Keywords: Cc:
Blocked by: Blocking:
Description

and it is not only inconvenient: it seems to be a bug.

The $.each function executes the function supplied as a 2nd parameter even for array positions that have never been filled (the 2nd argument passed to this function is then "undefined"). Why use the very efficient JQuery syntax if we end up having to write a more complex function to handle non-existing data?

Also, since the $.each function wastes time iterating over non-existing array elements, it can easily be HUNDREDS of times slower than the standard JS for(ind in array) construct, which is not affected by this problem.

On my computer with Firefox 3, iterating 100 times over a 2-element array with the highest index equal to 5000 takes... not even 1 ms with "for(ind in array)", and it takes 679 ms with $.each.

Attachments (0)
Change History (5)

Changed January 04, 2009 07:36PM UTC by balazs.endre comment:1

Using a for..in loop on an array can cause problems if you (or others) extended Array.prototype, looping through the numeric indices is much safer!

$.each is not intended to be used on huge empty arrays, you can easily write a function based on $.each that skips unnecessary elements :)

The native forEach method (if implemented) doesn't skip undefined properties either.

Changed January 04, 2009 09:21PM UTC by mmikeyy comment:2

I just recently experienced this problem of properties added to the prototype popping up amongst array elements when the array is traversed the wrong way (with a for/in loop).

Filtering out the object properties to keep only array elements can be achieved as follows, I think:

for (ind in array) {

if (!isNaN(ind)) continue;

//array element processing...

}

Is this not incredibly more efficient than filtering out possibly hundreds or thousands of non-existent numeric indices?

The reason for all these unused array indices is that the data comes from a database and the unique record number is used as key value when it is stored in arrays. I may have just a few elements with a very high key value stored in an array.

Any advice on other / better ways of doing things is welcome.

In the meanwhile, I think I will write a variant of the $.each iterator to more efficiently process arrays.

Changed January 04, 2009 09:29PM UTC by mmikeyy comment:3

Correction: the above code should read "if(isNaN(ind)) continue"...

Changed January 04, 2009 09:44PM UTC by balazs.endre comment:4

  • isNaN won't help much as all the indices "exist" less then the length property (more precisely they are undefined)
  • for objects you could use the hasOwnProperty method
  • but here this is unnecessary, just use a loop like this:
for(var i=0, l=array.length; i<l; i++){ 
  if(typeof array[i]=="undefined") continue;
  ...
}
  • function calls also take some (very little) time, with a simple loop there isn't any

And since this is just a bug tracker such topics are better suited on the mailing list: http://groups.google.com/group/jquery-en/

Changed January 11, 2009 03:57AM UTC by dmethvin comment:5

resolution: → invalid
status: newclosed

The for/in is not a safe way to deal with an Array because of the issues that balazs.endre mentions. jQuery.each is also used for array-like objects such as the arguments list of a function. Using for/in would break that.