长列表数据渲染优化

如何实现一次性渲染 10 万条数据?

这是数据模拟请求接口

// 数据接口请求模拟
const getList = () => {
  return new Promise((resolve, reject) => {
    let arr = [];
    for (i = 0; i < 100000; i++) {
      arr.push({
        id: i,
        title: i,
        imgUrl: "",
      });
    }
    resolve(arr);
  });
};

然后处理渲染数据总结了四种方法

  1. 17s(不做任何处理直接渲染的情况)
const renderList = async () => {
  console.time("列表时间");
  const list = await getList();
  list.forEach((item) => {
    const div = document.createElement("div");
    div.className = "flex";
    div.innerHTML = `<img src="${item.imgUrl}"/><span>${item.title}</span>`;
    container.appendChild(div);
  });
  console.timeEnd("列表时间");
};
renderList();
  1. 首先需要做分页的处理 + setTimeout 2s
const renderList = async () => {
  console.time("列表时间");
  const list = await getList();
  const total = list.length;
  const page = 0;
  const limit = 20;
  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.className = "flex";
        div.innerHTML = `<img src="${item.imgUrl}"/><span>${item.title}</span>`;
        container.appendChild(div);
      }
      render(page + 1)
    }, 0);
  };
  render(page)
  console.timeEnd("列表时间");
};
renderList();
  1. 分页 + requestAnimationFrame (请求动画帧)减少重排的次数)
    用window.requestAnimationFrame() 代替 setTimeout
const renderList = async () => {
  console.time("列表时间");
  const list = await getList();
  const total = list.length;
  const page = 0;
  const limit = 20;
  const totalPage = Math.ceil(total / limit);
  const render = (page) => {
    if (page >= totalPage) return;
    window.requestAnimationFrame(() => {
      for (let i = page * limit; i <= page * limit + limit; i++) {
        const item = list[i];
        const div = document.createElement("div");
        div.className = "flex";
        div.innerHTML = `<img src="${item.imgUrl}"/><span>${item.title}</span>`;
        container.appendChild(div);
      }
      render(page + 1);
    });
  };
  render(page);
  console.timeEnd("列表时间");
};
renderList();
  1. 最后最优的办法,在方法3的基础上用 document.createDocumentFragment() (创建文档碎片) 创建虚拟节点 1s不到
const renderList = async () => {
    console.time("列表时间");
    const list = await getList();
    const total = list.length;
    const page = 0;
    const limit = 20;
    const totalPage = Math.ceil(total / limit);
    const render = (page) => {
      if (page >= totalPage) return;
      window.requestAnimationFrame(() => {
        const fragment = document.createDocumentFragment()
        for (let i = page * limit; i <= page * limit + limit; i++) {
          const item = list[i];
          const div = document.createElement("div");
          div.className = "flex";
          div.innerHTML = `<img src="${item.imgUrl}"/><span>${item.title}</span>`;
          // 先塞进文档碎片
          fragment.appendChild(div);
        }
        // 一次性 appendChild
        container.appendChild(fragment)
        render(page + 1);
      });
    };
    render(page);
    console.timeEnd("列表时间");
};

renderList();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容