MKi*_*irk 4 javascript performance dom reflow
为了弄清楚我在问什么,这是我的例子(小提琴).
我有一个~500个随机名称的列表.我在顶部有一个输入,具有实时搜索功能.在每一个上keyup,输入的值都是,并且列表中的每个项目都与之匹配.隐藏不匹配的项目.
主观上,表现还可以,但不是很好.如果您快速键入,则列表更新前会有明显的暂停.我没有分析代码,但瓶颈几乎肯定是DOM的变化和它引起的回流.
我想知道是否可以"排队"这些更改,并且只在循环结束时实际应用它们.所以这将是一个巨大的回流,而不是很多小的回流.
在另一个版本的小提琴中,我使用了一个RegExp来更加喜欢匹配和演示.即使我在这个中使用了更多的DOM操作(添加/删除标签以启用匹配突出显示),性能也会大致相同.我也尝试在CSS中添加可见/隐藏类,只是设置元素' className因为那应该是更好的表现(搜索javascript回流和重绘stubbornella - 我不能发布超过2个链接)但在我的测试中(Firefox 54)我发现情况更糟.所以我不知道那里发生了什么.
我想我实际上问的是:如何让这段代码更快?
缓冲DOM的更新毫无意义,DOM本身在回流/重新渲染之前已经做好了.
你必须要做的是减少对DOM的更新,只使用廉价的交互,尽可能少的交互(其中"交互"包括getter).哦,永远不要使用强制回流的属性.
500个元素是相当可行的,你的第一个小提琴已经对我很敏感.在第二部分中,我发现了一些问题区域和可能的改进:
innerText不好.非常糟糕的.它强制进行回流,因为它考虑了样式并且不会返回不可见的文本(这也确实打破了你的小提琴).请textContent改用.innerHTML几乎一样糟糕,因为它需要调用HTML解析器.500次.有时候(对于大块)比手动更新DOM的每个部分要快,但在这里不行.而不是销毁和重新创建所有这些标签,而是将元素保留在DOM中.requestAnimationFrame而不是非常小setTimeout,以便DOM在呈现之前仅更新一次.new RegExp也相当昂贵.您只需要调用一次,而不是每个项目.listItems从DOM每个函数被调用的时间,但缓存功能之外阵列像你这样做list和search.你可以做得更好:还要缓存它们的内容和样式对象,这样你就不必通过DOM访问它们.所以一旦你修复了" Quick hacky way to remove <b>s"(正如你自己记录的那样),大多数问题都应该消失.这是我的方法的要点:
var search = document.getElementById('s');
var items = Array.from(document.getElementById('l').children, function(li) {
return {
text: li.textContent,
style: li.style,
pre: li.firstChild, // the text node
match: li.appendChild(document.createElement("span"))
.appendChild(document.createTextNode("")),
post: li.appendChild(document.createTextNode(""))
};
});
function searchAction() {
var term = search.value;
var re = new RegExp(term, 'i'); // case insensitive
for (var {text, style, pre, match, post} of items) {
var m = text.match(re);
if (m) {
pre.nodeValue = text.slice(0, m.index);
match.nodeValue = m[0];
post.nodeValue = text.slice(m.index + m[0].length);
show(style);
} else {
hide(style);
}
}
}
Run Code Online (Sandbox Code Playgroud)
看到更新的小提琴.