一次拿到10万条数据,如何进行渲染优化?

84 阅读1分钟

是否可以直接全部渲染?

答案肯定是否定的,一次性全部渲染,10万次回流,页面会非常卡顿,直接影响到用户体验。

采用RequestAnimationFrame + fragment(时间分片)

RequestAnimationFrame是什么?

requestAnimationFrame 是浏览器提供的一个用于优化动画性能的 API。它的作用是请求浏览器在下次重绘之前执行指定的回调函数,以保证动画的流畅性和性能。

相比于setTimeout和setInveral,对于时间的把控更为精确,如果屏幕的刷新率是60HZ,那么就是每隔1000ms/60 = 16.7ms左右执行一次,由系统来决定它的执行时机,保证了回调函数在屏幕每一次的刷新间隔中只被执行一次。

DocumentFragment(文档片段)

一种特殊的 DOM 节点,它可以作为一个轻量级的容器,用于临时存放 DOM 元素。文档片段本身不会直接插入到文档中,而是可以包含其他 DOM 元素,当文档片段插入到文档中时,它的子元素会被移动到目标位置,这样可以减少 DOM 操作的性能消耗。

            let pageCount = 20
            let total = 100000
            let startIndex = 0
            let container = document.getElementById('container')
            function loop(total) {
                  total -= pageCount
                  if (total <= 0) return
                  const count = Math.min(pageCount, total)
                  window.requestAnimationFrame(() => {
                        for (let i = 0; i < count; i++) {
                              const li = document.createElement('li')
                              li.innerText = `我是第${startIndex + i + 1}条数据`
                              container.appendChild(li)
                        }
                        startIndex += pageCount
                        loop(total)
                  })

            }
            loop(total)

以上代码仅使用requestAnimationFrame实现,渲染效果相对直接一次渲染流畅很多,但是也还有优化的空间,我们可以先把20条li节点临时存放在文档片段DocumentFragment中,然后再把文档片段挂载到dom上,这样一来,页面的回流次数就从100000减少到了100000 / 20 = 5000次,进一步的提升了加载速度。

            let pageCount = 20
            let total = 100000
            let startIndex = 0
            let container = document.getElementById('container')
            function loop(total) {
                  total -= pageCount
                  if (total <= 0) return
                  const count = Math.min(pageCount, total)
                  const fragement = document.createDocumentFragment()
                  window.requestAnimationFrame(() => {
                        for (let i = 0; i < count; i++) {
                              const li = document.createElement('li')
                              li.innerText = `我是第${startIndex + i + 1}条数据`
                              fragement.appendChild(li)
                        }
                        container.appendChild(fragement)
                        startIndex += pageCount
                        loop(total)
                  })

            }
            loop(total)