如何高性能渲染十万条数据?
May 29, 2023 ·
3 Min Read
当我们遇到需要渲染大量数据时,如果一次性进行渲染,往往可能会出现页面卡顿现象。
所以,一般有两种解决方法:
- 时间分片
- 虚拟列表(or 分页)
这里主要介绍时间分片方法。
涉及的知识:
setTimeout
- event loop
主要思路是:将一组大数据,进行定时循环分片渲染,直到渲染完毕。比如吃包子,一小口一小口吃,直到吃完,而不是一口一个大包子,小心咽不下。
提一下,为什么与 event loop 有关呢?因为 JS 的运行是先把所有微任务执行完毕后,再从栈中取下一个宏任务,当宏任务执行完毕,检查该宏任务是否有微任务,如果有则执行,反之继续取下一个宏任务,一直循环,直到栈被清空。而 setTimeout
则为宏任务。
所以 setTimeout
设置的时间实际是有偏差的。我提这个实际与时间分片关系不大,主要是如果想要更好的渲染效果,下文提到附加项。
例:
利用 slice
每次截取一段数据,利用 setTimeout
定时执行一次,直到所有数据渲染完成。(PS:思路是这样的,但不一定与我相同的实现方法)
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body><ul id="list"></ul>
<script> const ul = document.getElementById('list'); const arr = new Array(100000).fill(0);
function render(list, ele) { for (let i = 0; i < list.length; i++) { ul.appendChild(ele(i)); } }
function createLi(text) { const li = document.createElement('li'); li.innerHTML = text;
return li }
let loop = (function (data, count) { const d = data; const c = count; let start = 0; const pageCount = Math.ceil(d.length / count); return function() { setTimeout(() => { const list = d.slice(start * c, start * c + c); render(list, createLi) start += 1; if (start < pageCount) { arguments.callee() } }, 0); } })(arr, 20)
loop(); loop = null;</script></body></html>
附加:
还可以使用 window.requestAnimationFrame()
来代替 setTimeout
,此方法为要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
Last edited Feb 15