本文给出了三种写法,是按照性能和效率由低到高依次改进的,建议按照顺序来一步步加深理解。
setTimeout分页渲染
通过总数据条数total
,和每页限制的条数limit
,计算出总页数totalPage
,通过setTimeout
单独渲染每一页,从而减少渲染时间。
const renderList = async () => {
const list = await getList()
const total = list.length
const page = 0
const limit = 200
const totalPage = Math.ceil(total/limit)
const render = (page) => {
if (page >= totalPage) return
setTimeout(() => {
for (let i = page * limit; i < page * limit + limit; i++) {
const item = list[i]
const div = document.createElement('div')
div.innerHTML = `${item.content}`
container.appendChild(div)
}
})
render(page+1)
}
render(page)
}
requestAnimationFrame
window.requestAnimationFrame()
告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
将requestAnimationFrame
代替setTimeout
,可以减少频繁重排带来的性能损耗。
const renderList2 = async () => {
const list = await getList()
const total = list.length
const page = 0
const limit = 200
const totalPage = Math.ceil(total / limit)
const render = (page) => {
if (page >= totalPage) return
// 使用requestAnimationFrame代替setTimeout
requestAnimationFrame(() => {
for (let i = page * limit; i < page * limit + limit; i++) {
const item = list[i]
const div = document.createElement('div')
div.innerHTML = `${item.content}`
container.appendChild(div)
}
})
render(page + 1)
}
render(page)
}
文档碎片 + requestAnimationFrame
之前每创建一个div
就appendChild
一次,现在将每页的所有div
先填进Fragment
,再一次性appendChild
进容器,减少了appendChild
的次数,提高性能。
const renderList3 = async() => {
const list = await getList()
const total = list.length
const page = 0
const limit = 200
const totalPage = Math.ceil(total / limit)
const render = (page) => {
if (page >= totalPage) return
requestAnimationFrame(() => {
// 创建fragment
const fragment = document.createDocumentFragment()
for(let i = page * limit; i < page * limit + limit; i++) {
const item = list[i]
const div = document.createElement('div')
div.innerHTML = `${item.content}`
// 先填进fragment
fragment.appendChild(div)
}
// 再将fragment一次性appendChild
container.appendChild(fragment)
render(page + 1)
})
}
render(page)
}