今天写代码突然发现了俩个新api,以前都没怎么用过
我想很多小伙伴也有过大数据渲染到屏幕的苦恼,大部分是虚拟列表来解决这个问题
接下来我们换一种思路
上代码(应该是能看懂的)利用定时器,在时间内批量渲染
<script>
const total = 100000
let ul = document.getElementById('container')
let once = 20
let page = total / once
function loop(curTotal) {
if (curTotal <= 0) return
let pageCount = Math.min(curTotal, once)
setTimeout(() => {
for (let i = 0; i < pageCount; i++) {
let li = document.createElement('li')
li.innerHTML = ~~(Math.random() * total)
ul.appendChild(li)
}
loop(curTotal - pageCount)
}, 0)
}
loop(total)
</script>
但是这种方法会有个缺陷,显卡不好,滚动会不断白屏(小伙伴们可以自行尝试)(要老电脑)
并且这种方法,页面回流有十万次,次数太多了
于是我看到了一个api
requestAnimationFrame
equestAnimationFrame也是个定时器,不同于setTimeout,它的时间不需要我们人为指定,这个时间取决于当前电脑的刷新率,如果是 60Hz ,那么就是 16.7ms 执行一次,如果是 120Hz 那就是 8.3ms 执行一次(看大佬的原话,这个好像还不算是一个宏任务)下图是大佬发言
于是利用这个api 我改造一下代码
<script>
const total = 100000
let ul = document.getElementById('container')
let once = 20
let page = total / once
function loop(curTotal) {
if (curTotal <= 0) return
let pageCount = Math.min(curTotal, once)
window.requestAnimationFrame(() => {
for (let i = 0; i < pageCount; i++) {
let li = document.createElement('li')
li.innerHTML = ~~(Math.random() * total)
ul.appendChild(li)
}
loop(curTotal - pageCount)
})
}
loop(total)
</script>
新的问题来了如何解决页面回流十万次?,这个很显然是不利于页面渲染的,如果用上ui组件,页面一样卡顿
解决方案采用 createDocumentFragment
<script>
const total = 100000
let ul = document.getElementById('container')
let once = 20
let page = total / once
function loop(curTotal) {
if (curTotal <= 0) return
let pageCount = Math.min(curTotal, once)
window.requestAnimationFrame(() => {
let fragment = document.createDocumentFragment() // 创建一个虚拟文档碎片
for (let i = 0; i < pageCount; i++) {
let li = document.createElement('li')
li.innerHTML = ~~(Math.random() * total)
fragment.appendChild(li) // 挂到fragment上
}
ul.appendChild(fragment) // 现在才回流
loop(curTotal - pageCount)
})
}
loop(total)
</script>
createDocumentFragment是虚拟文档碎片,我们一次for循环产生 20 个li的过程中可以全部把真实dom挂载到createDocumentFragment上,然后再把createDocumentFragment挂载到真实dom上,这样原来需要回流十万次,现在只需要回流100000 / 20次。算是加速了20倍吗?