高性能插入 100000 个 DOM节点
#前端性能
目录
- 1. 总结
- 2. DocumentFragment + 虚拟列表
- 3. DocumentFragment + requestAnimationFrame 分批插入
- 4. DocumentFragment 一次性插入
- 5. innerHTML 模板字符串
- 6. 性能优化要点
- 7. 使用建议
- 8. 示例用法
1. 总结
- 下面按==性能从高到低==排序说明
- DocumentFragment + 虚拟列表
- DocumentFragment + requestAnimationFrame 分批插入
- DocumentFragment 一次性插入
- innerHTML 模板字符串
2. DocumentFragment + 虚拟列表
function renderList(total) {
const container = document.getElementById('container');
const fragment = document.createDocumentFragment();
const itemHeight = 20; // 假设每项高度20px
const visibleCount = Math.ceil(window.innerHeight / itemHeight);
// 创建虚拟滚动容器
const virtualContainer = document.createElement('div');
virtualContainer.style.height = `${total * itemHeight}px`;
virtualContainer.style.position = 'relative';
// 初始只渲染可视区域的内容
function renderItems(startIndex) {
fragment.textContent = ''; // 清空
const endIndex = Math.min(startIndex + visibleCount, total);
for(let i = startIndex; i < endIndex; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
div.style.position = 'absolute';
div.style.top = `${i * itemHeight}px`;
fragment.appendChild(div);
}
virtualContainer.textContent = '';
virtualContainer.appendChild(fragment);
}
// 监听滚动事件
container.addEventListener('scroll', () => {
const scrollTop = container.scrollTop;
const startIndex = Math.floor(scrollTop / itemHeight);
renderItems(startIndex);
});
container.appendChild(virtualContainer);
renderItems(0);
}
3. DocumentFragment + requestAnimationFrame 分批插入
function renderWithRAF(total) {
const container = document.getElementById('container');
const fragment = document.createDocumentFragment();
const batchSize = 500; // 每批处理500个
let currentIndex = 0;
function appendItems() {
const fragment = document.createDocumentFragment();
const end = Math.min(currentIndex + batchSize, total);
for(let i = currentIndex; i < end; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
container.appendChild(fragment);
currentIndex = end;
if(currentIndex < total) {
requestAnimationFrame(appendItems);
}
}
requestAnimationFrame(appendItems);
}
4. DocumentFragment 一次性插入
function renderAll(total) {
const container = document.getElementById('container');
const fragment = document.createDocumentFragment();
for(let i = 0; i < total; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
container.appendChild(fragment);
}
5. innerHTML 模板字符串
function renderWithInnerHTML(total) {
const container = document.getElementById('container');
const html = Array.from({ length: total }, (_, i) =>
`<div>Item ${i}</div>`
).join('');
container.innerHTML = html;
}
6. 性能优化要点
- 使用虚拟列表(最优方案)
- 只渲染可视区域的内容
- 监听滚动按需渲染
- 内存占用最小
- 性能最好
- 分批处理
- 使用
requestAnimationFrame
分批插入 - 避免长时间阻塞主线程
- 保持页面响应性
- 使用
- DocumentFragment
- 减少 DOM 操作次数
- 避免重排重绘
- 一次性插入
- 批量更新
- 使用 innerHTML 或模板字符串
- 减少 DOM 操作
- 注意 XSS 风险
7. 使用建议
- 数据量大时(>1000)推荐使用虚拟列表
- 数据量中等时(100-1000)可以用分批处理
- 数据量小时(<100)可以直接用 DocumentFragment
- 需要考虑内存占用时避免使用 innerHTML
8. 示例用法
// 虚拟列表(推荐)
renderList(100000);
// 分批处理
renderWithRAF(100000);
// 一次性插入
renderAll(100000);
// innerHTML方式
renderWithInnerHTML(100000);