首先告诉面试官, 这种设计不合理
如果非要这么做, 那再继续寻找解决方案
虚拟列表
浏览器能否处理
- js没问题
- 渲染到dom会非常卡顿
第三方lib
- Vue-virtual-scroll-list
- React-virtualiszed
自定义中间层
- 自定义中间层, 获取并拆分这10w条数据
- 成本比较高:
- 测试
- 调试
- 上线
- 监控
- 申请服务器
- 申请域名
时间切片
- 点击
按钮add往页面中添加30万个div - 利用时间切片性能优化
<div id="app">
<button class="btn">add</button>
</div>
const app = document.querySelector('#app')
const btn: any = document.querySelector('.btn')
btn.onclick = () => {
const add = (index: number) => {
const div: any = document.createElement('div')
div.innerText = index
app.appendChild(div)
}
// 执行 add 三十万次
performChunk(300000, add)
}
// 默认往requestIdleCallback队列添加异步任务
function performChunk(times: number, add: Function) {
let i = 0;
function unitWork(idle) {
const hasTime = () => idle.timeRemaining() > 0
while(hasTime() && i<=times) {
add(`这是第${i}个`)
i++
}
if(i<=times) {
requestIdleCallback(unitWork)
}
}
requestIdleCallback(unitWork)
}
分帧渲染
const arr = new Array(100000).fill(1);
const Test = function () {
const [count, defer] = useDefer(100)
/** defer(k/1000) 表示帧数大于 k/1000 时渲染该条数据, 每帧渲染1000条 */
return <>
{
arr.map((n, k) => {
return defer(k/1000) && <p key={k}>{n}</p>
})
}
</>
}
function useDefer(maxF = 100) {
const [f, setF] = useState(0)
useEffect(() => {
setAnimation((count) => {
setF(count)
}, maxF)
}, [])
function defer(n) {
return n < f
}
return [f, defer] as const
}
function setAnimation(cb: any, max: number, count=0) {
if(count > max) return
cb(count)
requestAnimationFrame(() => setAnimation(cb, max, count+1))
}