Reputation: 12597
Using the Timeline in the Chrome Developer Tools, I used this small piece of code to record events through innerHTML and appendChild methods:
<!DOCTYPE html>
<html>
<head>
<script>
function testInnerHTML(){
var wrap = document.getElementById('wrapper');
wrap.innerHTML = "test";
}
function testAppendChild(){
var wrap = document.getElementById('wrapper');
wrap.appendChild(document.createTextNode("test"));
}
</script>
</head>
<body>
<input type="button" value="innerHTML" onClick="testInnerHTML();"/>
<input type="button" value="appendChild" onClick="testAppendChild();"/>
<div id="wrapper"></div>
</body>
</html>
And I can see that :
In this sample, each event take nearly nothing to be processed and seems to happen more or less in parallel, but if you do this with a big html table for example, you will see that recalculating style may take several seconds and that layout will happen after that. So if we can avoid it, it's better !
I was thinking about using an appendChild with a document fragment to avoid parsing involved by innerHTML. But the time saved that way is lost by the recalculate style ...
I am using Chrome Version 23.0.1271.64 m
Do you have any idea why this happens ? Should I add something to the node I append to help the browser not to trigger a recalculate style event ?
PS: if you wonder about the double parsing event, you can refer to Why does a click setting innerHTML trigger two parsing events on Chrome?
Upvotes: 3
Views: 1684
Reputation: 32286
In WebKit, HTMLElement::setInnerHTML()
internally uses replaceChildrenWithFragment()
, which has the following special case:
if (hasOneTextChild(containerNode.get()) && hasOneTextChild(fragment.get())) {
toText(containerNode->firstChild())->setData(toText(fragment->firstChild())->data(), ec);
return;
}
as opposed to ContainerNode::appendChild()
, which just iteratively inserts nodes into the container and dispatches the respective events (e.g. DOMNodeInserted
.)
I agree this might use some optimization.
Upvotes: 2