限制 DOM 更新

在浏览器环境中运行时,JavaScript 中常见的错误是更频繁地更新 DOM。

这里的问题是 DOM 接口中的每次更新都会导致浏览器重新呈现屏幕。如果更新更改了页面中元素的布局,则需要重新计算整个页面布局,即使在最简单的情况下,这也是非常高性能的。重新绘制页面的过程称为回流,并可能导致浏览器运行缓慢甚至停止响应。

使用以下向列表中添加项目的示例说明了过于频繁地更新文档的结果。

请考虑以下包含 <ul> 元素的文档:

<!DOCTYPE html>
<html>
    <body>
        <ul id="list"></ul>
    </body>
</html>

我们将 5000 项添加到循环 5000 次的列表中(你可以在功能强大的计算机上尝试使用更大的数字来增加效果)。

var list = document.getElementById("list");
for(var i = 1; i <= 5000; i++) {             
    list.innerHTML += `<li>item ${i}</li>`;  // update 5000 times
}

在这种情况下,可以通过在一个 DOM 更新中批量处理所有 5000 个更改来提高性能。

var list = document.getElementById("list");
var html = "";
for(var i = 1; i <= 5000; i++) {
    html += `<li>item ${i}</li>`;
}
list.innerHTML = html;     // update once

函数 document.createDocumentFragment() 可以用作循环创建的 HTML 的轻量级容器。此方法比修改容器元素的 innerHTML 属性稍快(如下所示)。

var list = document.getElementById("list");
var fragment = document.createDocumentFragment();
for(var i = 1; i <= 5000; i++) {
    li = document.createElement("li");
    li.innerHTML = "item " + i;
    fragment.appendChild(li);
    i++;
}
list.appendChild(fragment);