3

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

<!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 触发布局事件
  • appendChild触发布局事件和重新计算样式事件 appendChild 触发布局并重新计算样式事件

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

我正在考虑使用带有文档片段的 appendChild 来避免 innerHTML 涉及的解析。但是以这种方式节省的时间被重新计算的样式丢失了......

我正在使用 Chrome 版本 23.0.1271.64 m

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

PS:如果对双解析事件有疑问,可以参考Chrome上为什么一个点击设置innerHTML会触发两个解析事件?

4

1 回答 1

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。)

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

于 2012-11-12T14:05:18.360 回答