按照高程上面的解释
1.使用createDocumentFragment
2.使用innerHTML
3.使用事件代理
4.dom渲染使用requestAnimationFrame进行优化
比如一道笔试题:向ul中添加十万个li。
普通方式为:
(function() {
const ulContainer = document.getElementById("ultest");
// 防御性编程
if (!ulContainer) {
return;
}
for (let i = 0; i < 100000; i++) {
const liItem = document.createElement("li");
liItem.innerText = i + 1;
// EventListener 回调函数的 this 默认指向当前节点,若使用箭头函数,得谨慎
liItem.addEventListener("click", function() {
alert(this.innerText);
});
ulContainer.appendChild(liItem);
}
})()
改进之后:
(function() {
const ulContainer = document.getElementById("ultest");
// 防御性编程
if (!ulContainer) {
return;
}
const total = 100000; // 插入数据的总数
const batchSize = 4; // 每次批量插入的节点个数,个数越多,界面越卡顿
const batchCount = total / batchSize; // 批处理的次数
let batchDone = 0; // 已完成的批处理个数
function appendItems() {
// 使用 DocumentFragment 减少 DOM 操作次数,对已有元素不进行回流
const fragment = document.createDocumentFragment();
for (let i = 0; i < batchSize; i++) {
const liItem = document.createElement("li");
liItem.innerText = batchDone * batchSize + i + 1;
fragment.appendChild(liItem);
}
// 每次批处理只修改 1 次 DOM
ulContainer.appendChild(fragment);
batchDone++;
doAppendBatch();
}
function doAppendBatch() {
if (batchDone < batchCount) {
// 在重绘之前,分批插入新节点
window.requestAnimationFrame(appendItems);
}
}
// kickoff
doAppendBatch();
// 使用 事件委托 ,利用 JavaScript 的事件机制,实现对海量元素的监听,有效减少事件注册的数量
ulContainer.addEventListener("click", function(e) {
const target = e.target;
if (target.tagName === "LI") {
alert(target.innerText);
}
});
})();
针对documentFragment.appendChild,也可以使用
for(let i = 0; i < 10; i++) {
html +=<li>item</li>
}
进行替换。耗时会花在字符串连接上。但是总体性能要比直接操作dom要快。