是否可以直接全部渲染?
答案肯定是否定的,一次性全部渲染,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)