In Internet Explorer 7, this code executes consistently in 47 ms:
f开发者_开发技巧unction updateObjectValues() {
$('.objects').html(12345678); // ~500 DIVs
}
however, this code executes consistently in 157 ms:
function updateObjectValues() {
$('.objects').html('12345678'); // ~500 DIVs
}
Passing a number is over 3x faster than a string. Why are these results so dramatically different? And, is there any way to help the performance of the string?
If you look at the jQuery source code (or even the unminified production version), you'll see that the if (typeof value === "string" ...
branch of the code is significantly more complex than the final else
version that will occur when you pass in a number.
Here's the 1.4.4 code for if the value is a string:
} else if ( typeof value === "string" && !rnocache.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
if ( this[i].nodeType === 1 ) {
jQuery.cleanData( this[i].getElementsByTagName("*") );
this[i].innerHTML = value;
}
}
// If using innerHTML throws an exception, use the fallback method
} catch(e) {
this.empty().append( value );
}
}
Here's what it does with a number:
} else {
this.empty().append( value );
}
Clearly, the overhead of all those additional checks and function calls add up. I mean, even just in the if
statement at the top, there are three regular expression tests, a map lookup, and a string being made lower case — and that's before we get into the body of the statement (if we do, perhaps one of the checks returns false
), which involves a further regex (as part of a parameterized replace) and a loop...
I just ran a test and it seemed to confirm my original notion:
.text(string)
is as fast as .html(number)
ergo there must be string parsing overhead in .html(string)
Whether this overhead is in ie7 or in jQuery is not clear to me. Ie8 doesn't seem to have the same problem, which would suggest that the problem is not i jQuery, but then ie8 has a much faster js engine than ie7...
Numbers can be stored binary, possibly in a single register. Strings have to be stored as, well, a string, in memory. So an optimizing interpreter or JIT-compiler will take advantage of the possible speed an integer provides.
Also, as Martin Jespersen points out, the html() function may handle strings differently than numbers, performing more work on it - if it is aware of the differences. Kudos to Martin there.
As T.J. Crowder points out, a look at the source reveals that the code path is quite different for a string; ironically, the associated comment suggests that this is in an attempt to exploit a "shortcut":
html: function( value ) {
if ( value === undefined ) {
return this[0] && this[0].nodeType === 1 ?
this[0].innerHTML.replace(rinlinejQuery, "") :
null;
// See if we can take a shortcut and just use innerHTML
} else if ( typeof value === "string" && !rnocache.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
if ( this[i].nodeType === 1 ) {
jQuery.cleanData( this[i].getElementsByTagName("*") );
this[i].innerHTML = value;
}
}
// If using innerHTML throws an exception, use the fallback method
} catch(e) {
this.empty().append( value );
}
} else if ( jQuery.isFunction( value ) ) {
this.each(function(i){
var self = jQuery( this );
self.html( value.call(this, i, self.html()) );
});
} else {
this.empty().append( value );
}
return this;
},
精彩评论