无限滚动实现详解与实战中遇到的那些坑

惠泽 ☘︎ 优化 阅读 2,147
赞 145 收藏
二维码
手机扫码查看
反馈

优化前:卡得不行

最近我在做一个项目,需要实现一个无限滚动的页面。一开始我用的是比较简单的实现方式,就是每次滚动到底部时,通过AJAX请求获取新的数据,然后动态添加到页面上。结果呢,优化前卡得受不了,用户滚动页面时,动不动就卡顿,体验极差。

无限滚动实现详解与实战中遇到的那些坑

找到毛病了!

为了解决这个问题,我先用了一些工具来定位问题所在。主要是用了Chrome的开发者工具,尤其是Performance面板,记录了一次完整的滚动过程,发现主要问题是DOM操作太多,每次加载新数据时都要重新渲染大量元素,导致浏览器压力大,性能下降。

另外,我还发现网络请求频繁,每次加载的数据量也不小,这也拖慢了页面响应速度。

优化后:流畅多了

经过一番折腾,我试了几种方案,最后这个效果最好。下面我分享一下具体的优化方法。

减少DOM操作

首先,我要解决的是DOM操作过多的问题。原来的代码是这样的:

window.addEventListener('scroll', function() {
  if (isBottom()) {
    fetch('https://jztheme.com/api/data')
      .then(response => response.json())
      .then(data => {
        const container = document.getElementById('data-container');
        data.forEach(item => {
          const div = document.createElement('div');
          div.textContent = item.name;
          container.appendChild(div);
        });
      });
  }
});

这里每次加载新数据时,都要创建多个DOM元素并逐个添加到容器中,效率非常低。我改成了批量插入DOM元素的方式,这样可以减少重绘次数:

window.addEventListener('scroll', function() {
  if (isBottom()) {
    fetch('https://jztheme.com/api/data')
      .then(response => response.json())
      .then(data => {
        const container = document.getElementById('data-container');
        const fragment = document.createDocumentFragment();
        data.forEach(item => {
          const div = document.createElement('div');
          div.textContent = item.name;
          fragment.appendChild(div);
        });
        container.appendChild(fragment);
      });
  }
});

这样优化后,DOM操作明显减少,性能提升了不少。

懒加载图片

除了DOM操作,我还注意到页面中的图片也是性能瓶颈之一。于是我引入了懒加载机制,只有当图片进入视口时才加载它们。原代码是这样的:

Image 1
Image 2

优化后的代码如下:

Image 1
Image 2

然后在JavaScript中初始化懒加载库:

import lazySizes from 'lazysizes';

document.addEventListener('DOMContentLoaded', () => {
  lazySizes.init();
});

这样,图片加载不会阻塞页面滚动,性能也得到了显著提升。

优化网络请求

最后,我还优化了网络请求。原来每次请求的数据量较大,导致加载时间较长。我将每次请求的数据量减小,并且使用了缓存策略,避免重复请求相同的数据。

原来的代码是这样的:

fetch('https://jztheme.com/api/data?limit=50')
  .then(response => response.json())
  .then(data => {
    // 处理数据
  });

优化后的代码如下:

const API_URL = 'https://jztheme.com/api/data';
const cache = new Map();

function fetchData(page) {
  if (cache.has(page)) {
    return Promise.resolve(cache.get(page));
  }
  return fetch(${API_URL}?page=${page}&limit=10)
    .then(response => response.json())
    .then(data => {
      cache.set(page, data);
      return data;
    });
}

window.addEventListener('scroll', function() {
  if (isBottom()) {
    const nextPage = getNextPage();
    fetchData(nextPage).then(data => {
      // 处理数据
    });
  }
});

通过这种方式,不仅减少了每次请求的数据量,还利用了缓存机制,提升了整体性能。

性能数据对比

经过这些优化后,性能有了明显的提升。具体数据如下:

  • 优化前:加载时间平均5秒
  • 优化后:加载时间平均800毫秒

从数据上看,性能提升了近6倍,用户体验也好了很多。

总结

以上是我的优化经验,主要集中在减少DOM操作、懒加载图片和优化网络请求三个方面。希望对你有帮助。如果有更好的方案,欢迎评论区交流。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论