35、js - 面试 - 如何一次渲染10万条数据?
如何一次渲染10万条数据?
面试官想了解:面试者对原生js底层的了解、对渲染机制的理解。
思路:
第一种方案:分页 + setTimeout()
第二种方案:分页 + window.requestAnimationFrame()减少重排
第三种方案:分页 + window.requestAnimationFrame() + document.createDocumentFragment()文档碎片
(方案一到方案三,渲染所需的时间逐渐较少,方案一大概要2秒,后面2个方案所需的时间就更少)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>如何一次渲染10万条数据?</div>
<div>面试官想了解:面试者对原生js底层的了解、对渲染机制的理解</div>
<script>
// 模拟请求接口数据
const getData = () => {
return new Primise((resolve, reject) => {
});
};
// 第一种方案:分页 + setTimeout()
const renderList1 = async () => {
console.time('开始分页');
const data = await getData();
const total = data.length;
const page = 0; // 首页默认是0页
const limit = 10; // 每页限制显示10条
const totalPage = Math.ceil(total / limit); // 页数需要往上取整
const render = (page) => {
// if (page >= totalPage) return; // 如果page的值大于等于totalPage,就不再往下走
// setTimeout是宏任务,那么就会依次执行任务队列里的任务
setTimeout(() => {
for (let i = page * limit; i < page * limit + limit; i++) {
const item = list[i];
const div = document.createElement('div');
div.innerHTML = `<span>${item.text}</span>`;
document.body.appendChild(div);
}
render(page + 1);
}, 0);
}
render(page);
console.timeEnd('结束分页');
}
// 第二种方案:分页 + window.requestAnimationFrame()减少重排
// 用requestAnimationFrame 代替 setTimeout
const renderList2 = async () => {
console.time('开始分页');
const data = await getData();
const total = data.length;
const page = 0; // 首页默认是0页
const limit = 10; // 每页限制显示10条
const totalPage = Math.ceil(total / limit); // 页数需要往上取整
const render = (page) => {
// requestAnimationFrame减少重排
requestAnimationFrame(() => {
for (let i = page * limit; i < page * limit + limit; i++) {
const item = list[i];
const div = document.createElement('div');
div.innerHTML = `<span>${item.text}</span>`;
document.body.appendChild(div);
}
render(page + 1);
}, 0);
}
render(page);
console.timeEnd('结束分页');
}
// 第三种方案:分页 + window.requestAnimationFrame() + document.createDocumentFragment()文档碎片
// document.createDocumentFragment()文档碎片是dom节点,但是并不是主dom树的一部分,
const renderList3 = async () => {
console.time('开始分页');
const data = await getData();
const total = data.length;
const page = 0; // 首页默认是0页
const limit = 10; // 每页限制显示10条
const totalPage = Math.ceil(total / limit); // 页数需要往上取整
const render = (page) => {
// 创建一个文档碎片
const fragment = document.createDocumentFragment();
requestAnimationFrame(() => {
for (let i = page * limit; i < page * limit + limit; i++) {
const item = list[i];
const div = document.createElement('div');
div.innerHTML = `<span>${item.text}</span>`;
// 先塞进文档碎片
fragment.appendChild(div);
}
// 再一次性appendChild
document.body.appendChild(fragment);
render(page + 1);
}, 0);
}
render(page);
console.timeEnd('结束分页');
}
</script>
</body>
</html>