setTimeout(() => { // 插入十万条数据 const total = 100000; // 一次插入的数据 const once = 20; // 插入数据需要的次数 const loopCount = Math.ceil(total / once); let countOfRender = 0; const ul = document.querySelector('ul'); // 添加数据的方法 function add() { const fragment = document.createDocumentFragment(); for(let i = 0; i < once; i++) { const li = document.createElement('li'); li.innerText = Math.floor(Math.random() * total); fragment.appendChild(li); } ul.appendChild(fragment); countOfRender += 1; loop(); } function loop() { if(countOfRender < loopCount) { window.requestAnimationFrame(add); } } loop(); }, 0)
原理:渲染大数据时,合理使用createDocumentFragment和requestAnimationFrame,将操作切分为一小段一小段执行。
documentFragment:
是一个虚拟的Dom列表,可以储存待处理的xml片段(el元素),因为他不在真实的Dom结构中,所以对它所做的操作不会触发浏览器的回流,只会在他插入dom的时候触发一次而已。
上面把多个动态生成的div插入到了虚拟节点里,在最后完成之后只做了一次插入,这样就只会触发一次回流。
但是在数量太多的时候,哪怕是一次插入,也会因为浏览器渲染不过来导致失去响应,这时候就需要增加一定的时间间隔,可以使用setTimeout,也可以使用一个api------requestAnimationFrame
requestAnimationFrame()
1.方法是为了动画 专门使用的api,在通常的动画中会定义一个定时器来几秒几秒的发生变化,但是为了性能和更加方便,它提供了这个可以在1秒钟运行大约60次(≈16.7ms)回调的api。
而且会把这一刻所有的dom操作缓存起来,在一次回流重绘中完成操作,它的每次调用并不是指定时间的,而是跟紧浏览器的刷新频率,所以可以做到:在浏览器的刷新频率时进行回流,保证性能效率。
当页面不是激活状态的情况下,这个函数将会停止回调,进行暂停来节省cpu操作。激活时再继续。
在元素隐藏时不会进行重绘回流。
2.它的返回值为一个long的标识符,和settimeout一样,可以调用cancelAnimationFrame()传入这个标识符来取消这个回调。
使用这个可以在浏览器下一次’刷新’的时候运行指定的回调,在这里来插入这多个节点。
使用这样可以大批量插入很多数据 页面也不会失去响应卡住,可以保证比较好的性能