后端一次性返回10万条数据

58 阅读1分钟

首先告诉面试官, 这种设计不合理

如果非要这么做, 那再继续寻找解决方案

虚拟列表

浏览器能否处理

  • 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))
}