JBE
JBE

Reputation: 12597

Why appendChild triggers Recalculate Style whereas setting innerHTML don't on Chrome?

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

Answers (1)

Alexander Pavlov
Alexander Pavlov

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

Related Questions