jQuery.fn.each vs. jQuery.fn.quickEach
JavaScript performance comparison
Info
Fast alternative to $.fn.each(func). Most usage of fn.each immediately evaluates $(this) - which is really expensive. This version changes this so that it already points to a single-element jQuery object.
Notes:
The callback function is normally much slower than
eachso the benefit ofquickerEachoften isn't dramatic. A simple for-loop may be more suitable.Your callback function MUST NOT call
quickEach(i.e. nesting).Your callback function MUST NOT store the value of
thisto a closure variable (I accidentally did once - and it took me over an hour to track the problem down).Don't be tempted to replace the jQuery
eachmethod with this.
My previous implementation (48) was bobbins because modern JS engines use short-circuiting to avoid doing work ... and there was a bug that you could drive a bus through.
Preparation code
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js">
</script>
<script>
var a = $('<div/>').append(Array(100).join('<a></a>')).children();
var arr = $.makeArray(a);
jQuery.fn.betterEach = (function() {
var jq = jQuery([1]);
var slice = Array.prototype.slice;
var el;
return function(c) {
var iter = function(e, i) {
el = jq[0] = e;
c.call(jq, i, el);
};
slice.call(this).forEach(iter);
jq[0] = 1;
return this;
}
})();
// Modified quickEach plugin
jQuery.fn.quickerEach = (function() {
var jq = jQuery([1]);
return function(c) {
var i = -1, el;
try {
while (el = jq[0] = this[++i] && c.call(jq, i, el) !== false);
} catch (e) {
jq[0] = 1;
throw e;
}
jq[0] = 1;
return this;
};
}());
// Modified quickEach plugin
jQuery.fn.quickerEach2 = (function() {
var jq = jQuery([1]);
return function(c) {
var i = -1, el;
try {
while (el = jq[0] = this[++i]&& c.call(jq[0], i, el) !== false);
} catch (e) {
jq[0] = 1;
throw e;
}
jq[0] = 1;
return this;
};
}());
jQuery.fn.quickerEach3 = (function() {
return function(c) {
var i = -1, el;
try {
while (el = this[++i] && c.call(el, i) !== false);
} catch (e) {
throw e;
}
return this;
};
}());
// James Padolsey's quickEach plugin
jQuery.fn.quickEach = (function() {
var jq = jQuery([1]);
return function(c) {
var i = -1, el, len = this.length;
try {
while (++i < len && (el = jq[0] = this[i]) && c.call(jq, i, el) !== false);
} catch (e) {
delete jq[0];
throw e;
}
delete jq[0];
return this;
};
}());
</script>
Preparation code output
Test runner
Warning! For accurate results, please disable Firebug before running the tests. (Why?)
Java applet disabled.
| Test | Ops/sec | |
|---|---|---|
.each() |
|
pending… |
.quickEach() |
|
pending… |
.quickerEach() |
|
pending… |
For loop |
|
pending… |
quickerEach2 |
|
pending… |
quickerEach3 |
|
pending… |
Compare results of other browsers
Revisions
You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:
- Revision 1: published by James Padolsey
- Revision 2: published by "Cowboy" Ben Alman
- Revision 3: published by "Cowboy" Ben Alman
- Revision 9: published by NilColor
- Revision 13: published
- Revision 14: published
- Revision 15: published
- Revision 18: published
- Revision 19: published
- Revision 22: published by mhitza
- Revision 27: published
- Revision 28: published by Test
- Revision 29: published
- Revision 30: published by Erwan Legrand
- Revision 31: published
- Revision 32: published
- Revision 33: published
- Revision 34: published by Vaibhav
- Revision 35: published
- Revision 36: published
- Revision 37: published
- Revision 38: published
- Revision 39: published
- Revision 41: published by Jason
- Revision 42: published by Dim
- Revision 47: published by Andy Harman
- Revision 48: published by Andy Harman and last updated
- Revision 50: published by private_face
- Revision 54: published
- Revision 56: published by David Seigle
- Revision 58: published by Andy Harman
- Revision 59: published by David Seigle
- Revision 63: published by Andy Harman
- Revision 64: published by roviury
- Revision 66: published by Andy Harman
- Revision 69: published by Andy Harman and last updated
- Revision 70: published
- Revision 71: published
- Revision 73: published
- Revision 74: published
- Revision 76: published
- Revision 77: published
- Revision 78: published by Jeffrey
- Revision 79: published
- Revision 80: published
- Revision 81: published by nod_ and last updated
- Revision 82: published by Andy Harman
- Revision 83: published by Kirill
- Revision 85: published
- Revision 87: published
- Revision 88: published
1 comment
Several of the tests have errors: while (el = jq[0] = this[++i]&& c.call(jq[0], i, el) !== false); Should be: while ((el = jq[0] = this[++i]) && c.call(jq[0], i, el) !== false);
I think that the author may have based this revision on my buggy revision.
Also, the whole point of this test scenario is to create a version of $().each() that provides a jQuery object to the called-method, rather than a DOM element.
Revision 69 is still the best example.