How to improve performance of inserting text into an HTML element?
In Firefox, I am inserting text into ~500 DIVs using this code:
$(".divs").text("default"); // ~500 DIVs
On my computer, this consistently takes 9ms if the DIVs are empty. However, this same code consistently takes 18ms if the DIVs already contain text.
Why is it that an empty DIV is 2x faster at inserting text (does jQuery need to empty the DIV first)? And, is there any way to improve the performance of replacing text in a DIV that already contains text?
Note: In IE 7, the speed differences were not as dramatic. Inserting text in an empty DIV was about 1.5x faster.开发者_开发问答
If you want the fastest solution for all browsers use textContent
if supported and fallback to innerText
/ innerHTML
otherwise [Test] (knowing the gotchas).
/**
* Replaces text for all elements in the given array.
* @param {Array} elems
* @param {String} text
*/
var replaceText = (function(){
var dummy = document.createElement("div");
dummy.innerHTML = "text";
var TEXT = (dummy.textContent === 'text') ? 'textContent' : 'innerText';
return function(elems, text) {
for (var i = elems.length; i--;) {
elems[i][TEXT] = text;
}
};
})();
Faster than jQuery text:
- 4x on IE 8
- 2.2x on Firefox 4b11
- 1.3x on Chrome
If the text you are inserting does NOT need to be escaped, then you might want to try the following:
$(".div").each(function(){
this.innerHTML = "default";
});
jQuery does some processing to the text when you use the method .text()
.
We need to be aware that this method escapes the string provided as necessary so that it will render correctly in HTML. To do so, it calls the DOM method
.createTextNode()
, which replaces special characters with their HTML entity equivalents (such as < for <).
Edit
To avoid the penalty of the .each()
method you can try the following:
var divs = $(".divs"),
i = 0,
len = divs.length;
while(len--) {
divs[len].innerHTML = "default";
}
If that doesn't get you any performance gains then it's definitely a browser implementation issue. At least that would rule out jQuery performance issues/bugs.
You can gain performance by reusing an existing text node.
A DIV element that contains only text, is a DOM element that contains one child node whose type is a text node. The text content is stored within this text node, and not within its parent DIV element.
The main problem with methods such as .text() in JQuery, or .innerHTML() in HTML DOM, or even .innerText() and .textContent(), is that they all create a new text node (even if one exists already). More specifically, all methods listed above start by removing all DOM child nodes, including an eventually pre-existing text node (this is also done by the implementations of innerHTML, innerText and textContent). This leaves the context element (the DIV, in your case) empty, without any children at all. They then create a new child node of type text node, assigning the new text to it, and appending it to the context element. innerHTML furthermore attempts to parse the input HTML string and constructs a DOM fragment out of it.
The fastest method that I know for replacing an existing text node is as follows:
var divs = $(".divs").get(),
len = divs.length;
while(--len) {
divs[len].firstChild.data = "default";
}
This method does not create a new child node, but merely replaces the text of the existing text node. Obviously, this method assumes that the text node exists already. For this to work, your initial document may be initialized with any non-empty text inside the DIVs (and excluding any other child elements).
Yes, the reason for this method to be slower when elements have child elements is because jQuery's .text()
method first runs the .empty()
method and then .append(document.createTextNode(text))
From jQuery.text
// ...
return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
// ...
The reason I'm pointing out this is that .empty()
method calls .cleanData()
method that removes any data and/or events associated with its child nodes, and then, does a standard .removeChild()
method on all its child nodes to remove them, which is the main reason why divs that already contain text are slower to update.
The solution to your problem, is to write your own, vanilla, javaScript functions for updating the text of your divs, but make sure you're not attaching any click events or data to them via jQuery, since you will most definitely have some memory leaks.
If you don't need to escape html tags (ie replacing <a>
with <a>
) then .html might be faster. Also yes it does need to empty the divs before replacing it with the new content.
精彩评论