时间分片渲染长列表时卡顿怎么办?

Des.利利 阅读 11

我在用时间分片优化一个几千条数据的列表,每帧只渲染10条,但滚动时还是明显卡顿。是不是我的切片逻辑有问题?

我试过用 requestIdleCallback,也试过用 setTimeout 拆分任务,但效果都不太理想。下面是我目前的简化代码:

function renderInChunks(items, chunkSize = 10) {
  let index = 0;
  function renderChunk() {
    const fragment = document.createDocumentFragment();
    for (let i = 0; i < chunkSize && index < items.length; i++, index++) {
      const el = document.createElement('div');
      el.textContent = items[index];
      fragment.appendChild(el);
    }
    container.appendChild(fragment);
    if (index < items.length) {
      requestIdleCallback(renderChunk);
    }
  }
  renderChunk();
}
我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
シ瑞瑞
シ瑞瑞 Lv1
你的问题在于 chunkSize 太小了,每次只渲染10条,调度开销比实际渲染工作还大。

requestIdleCallback 这货在滚动时基本不会触发——浏览器正忙着处理滚动事件呢,哪有空闲时间给你?所以你设置的10条可能攒半天才能执行一次,体验反而更差。

改用 requestAnimationFrame 试试,把 chunkSize 加大:

function renderInChunks(items, chunkSize = 100) {
let index = 0;

function renderChunk() {
const fragment = document.createDocumentFragment();
const end = Math.min(index + chunkSize, items.length);

for (; index < end; index++) {
const el = document.createElement('div');
el.textContent = items[index];
fragment.appendChild(el);
}

container.appendChild(fragment);

if (index < items.length) {
requestAnimationFrame(renderChunk);
}
}

renderChunk();
}


把 chunkSize 调到 50-200 之间,requestIdleCallback 换成 requestAnimationFrame。这样每帧都有机会执行,调度开销也降下来了。

不过说真的,几千条数据与其这么搞,不如直接上虚拟列表——只渲染可视区域内的二三十条,滚动时动态计算偏移量替换内容。这是业界标准做法,性能比时间分片强得多。react-window 或者 vue-virtual-scroller 都有现成的轮子可以直接用。
点赞 1
2026-03-10 21:17