为什么appendChild触发重新计算样式而在Chrome上设置innerHTML?

时间:2012-11-12 12:54:02

标签: javascript html google-chrome google-chrome-devtools

使用Chrome开发者工具中的时间轴,我使用这一小段代码通过 innerHTML appendChild 方法录制事件:

<!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>

我可以看到:

  • innerHTML 会触发布局事件 innertHTML triggers layout event
  • appendChild 触发布局事件和重新计算样式事件 appendChild triggers layout and recalculate style events

在这个示例中,每个事件几乎不需要处理任何事情,并且似乎或多或少地并行发生,但是如果您使用大型html表执行此操作,您将看到重新计算的样式可能需要几秒钟,布局将在此之后发生。所以,如果我们能够避免它,那就更好了!

我在考虑使用带有文档片段的appendChild来避免innerHTML涉及的解析。但重新计算的风格使得节省的时间丢失了......

我使用的是Chrome版本23.0.1271.64 m

你知道为什么会这样吗? 我应该向我追加的节点添加一些内容,以帮助浏览器不触发重新计算样式事件吗?

PS:如果您想知道双重解析事件,可以参考Why does a click setting innerHTML trigger two parsing events on Chrome?

1 个答案:

答案 0 :(得分:2)

在WebKit中,HTMLElement::setInnerHTML()内部使用replaceChildrenWithFragment(),其中包含以下特殊情况:

if (hasOneTextChild(containerNode.get()) && hasOneTextChild(fragment.get())) {
    toText(containerNode->firstChild())->setData(toText(fragment->firstChild())->data(), ec);
    return;
}

而不是ContainerNode::appendChild(),它只是迭代地将节点插入容器并调度相应的事件(例如DOMNodeInserted。)

我同意这可能会使用一些优化。