139邮箱网页版
81.38MB · 2025-10-23
那是一个普通的下午,我正悠哉地喝着咖啡,准备轻松完成一个“列表渲染”的小需求。后端同事发来消息:
我点开接口一看,整个人差点从椅子上滑下来:
10 万条数据!
脑子里立刻浮现出一种画面:就像港口突然迎来一艘超级货船,把几十万件货物一股脑儿砸到我面前,而我却只有一辆小推车去搬运。
但我还是硬着头皮上了,写下最直观的循环渲染:
const container = document.querySelector(".list-container");
const dataList = new Array(100000).fill('我是数据项').map((t, i) => `${t} - ${i + 1}`);
for (let i = 0; i < dataList.length; i++) {
const div = document.createElement('div');
div.innerText = dataList[i];
container.appendChild(div);
}
结果毫不意外:
这就像把全部货物直接砸在港口,结果不仅搬运停滞,还把整个码头压塌了。
我盯着屏幕发呆,心想:
“难道就没有一种方法,可以像分批卸货一样,把这些数据一点点渲染到页面里?”
就在这时,我想起一个被我长期忽视的 API:requestAnimationFrame
。
它的特性正好符合我的需求:
16.6ms
一次)于是,我决定换一种思路:分批渲染
。
function renderBigData(data, chunkSize = 50) {
const container = document.querySelector(".list-container");
let index = 0;
function renderChunk() {
const chunkEnd = Math.min(index + chunkSize, data.length);
const fragment = document.createDocumentFragment();
for (; index < chunkEnd; index++) {
const div = document.createElement('div');
div.innerText = data[index];
fragment.appendChild(div);
}
container.appendChild(fragment);
if (index < data.length) {
requestAnimationFrame(renderChunk); // 下一帧继续
}
}
renderChunk();
}
// 测试渲染 1 万条数据
const dataList = new Array(10000).fill('我是数据项').map((t, i) => `${t} - ${i + 1}`);
renderBigData(dataList);
页面不卡顿,每次只渲染 50 条,主线程得以喘息
用户依然能点击、滚动、输入
渲染过程像流水一样自然,不再“一刀切”
然而,问题并没有结束。
如果数据量达到 几十万甚至上百万条,哪怕分批渲染,DOM 仍然会堆积如山。
这时,真正的“性能核武器”登场了:虚拟滚动
。
原理就像“橱窗展示”
简单代码示例:
function renderVirtualScroll(data, container, itemHeight = 30) {
const viewportHeight = container.clientHeight;
const visibleCount = Math.ceil(viewportHeight / itemHeight);
let startIndex = 0;
function updateVisibleItems() {
const endIndex = startIndex + visibleCount;
const visibleData = data.slice(startIndex, endIndex);
container.innerHTML = '';
visibleData.forEach(item => {
const div = document.createElement('div');
div.style.height = `${itemHeight}px`;
div.textContent = item;
container.appendChild(div);
});
}
container.addEventListener('scroll', () => {
startIndex = Math.floor(container.scrollTop / itemHeight);
updateVisibleItems();
});
updateVisibleItems();
}
这样,无论数据量有多大,DOM 中真正存在的始终只有几十个元素,性能丝滑无比。
方案 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
直接渲染 | < 5k 条数据 | 简单粗暴 | 数据量一大就爆炸 |
分批渲染 (rAF) | 5k ~ 10w 条 | 页面不卡顿,实现简单 | DOM 节点仍很多 |
虚拟滚动 | 10w+ 条 | 性能极致,内存占用低 | 实现较复杂 |
前端性能优化,不只是让代码能跑,而是让用户感到“丝滑”。
如果把数据渲染比作一场货物运输:
而 requestAnimationFrame
,就是那个让运输过程变得优雅、从容的调度员;
所以下次,当你也遇到“数据海啸”时,交给它吧。