如何实现一次性渲染 10 万条数据?
这是数据模拟请求接口
// 数据接口请求模拟
const getList = () => {
return new Promise((resolve, reject) => {
let arr = [];
for (i = 0; i < 100000; i++) {
arr.push({
id: i,
title: i,
imgUrl: "",
});
}
resolve(arr);
});
};
然后处理渲染数据总结了四种方法
- 17s(不做任何处理直接渲染的情况)
const renderList = async () => {
console.time("列表时间");
const list = await getList();
list.forEach((item) => {
const div = document.createElement("div");
div.className = "flex";
div.innerHTML = `<img src="${item.imgUrl}"/><span>${item.title}</span>`;
container.appendChild(div);
});
console.timeEnd("列表时间");
};
renderList();
- 首先需要做分页的处理 + setTimeout 2s
const renderList = async () => {
console.time("列表时间");
const list = await getList();
const total = list.length;
const page = 0;
const limit = 20;
const totalPage = Math.ceil(total / limit);
const render = (page) => {
if (page >= totalPage) return;
setTimeout(() => {
for (let i = page * limit; i <= page * limit + limit; i++) {
const item = list[i];
const div = document.createElement("div");
div.className = "flex";
div.innerHTML = `<img src="${item.imgUrl}"/><span>${item.title}</span>`;
container.appendChild(div);
}
render(page + 1)
}, 0);
};
render(page)
console.timeEnd("列表时间");
};
renderList();
- 分页 + requestAnimationFrame (请求动画帧)减少重排的次数)
用window.requestAnimationFrame() 代替 setTimeout
const renderList = async () => {
console.time("列表时间");
const list = await getList();
const total = list.length;
const page = 0;
const limit = 20;
const totalPage = Math.ceil(total / limit);
const render = (page) => {
if (page >= totalPage) return;
window.requestAnimationFrame(() => {
for (let i = page * limit; i <= page * limit + limit; i++) {
const item = list[i];
const div = document.createElement("div");
div.className = "flex";
div.innerHTML = `<img src="${item.imgUrl}"/><span>${item.title}</span>`;
container.appendChild(div);
}
render(page + 1);
});
};
render(page);
console.timeEnd("列表时间");
};
renderList();
- 最后最优的办法,在方法3的基础上用 document.createDocumentFragment() (创建文档碎片) 创建虚拟节点 1s不到
const renderList = async () => {
console.time("列表时间");
const list = await getList();
const total = list.length;
const page = 0;
const limit = 20;
const totalPage = Math.ceil(total / limit);
const render = (page) => {
if (page >= totalPage) return;
window.requestAnimationFrame(() => {
const fragment = document.createDocumentFragment()
for (let i = page * limit; i <= page * limit + limit; i++) {
const item = list[i];
const div = document.createElement("div");
div.className = "flex";
div.innerHTML = `<img src="${item.imgUrl}"/><span>${item.title}</span>`;
// 先塞进文档碎片
fragment.appendChild(div);
}
// 一次性 appendChild
container.appendChild(fragment)
render(page + 1);
});
};
render(page);
console.timeEnd("列表时间");
};
renderList();