返回

一次聊透页面加载海量数据时如何保持丝滑体验?

前端

大家都有过这样的体验,在我们的日常使用互联网服务时,加载某个页面的时候,当数据量非常庞大时,会让人有一种卡顿的感觉,甚至有的时候这个页面加载不出来就转圈圈,此时此刻,我们只有耐心等待着页面加载完才可以进行正常的操作,然而有时候这个时间会很久,让我们失去耐心,关闭这个页面。

造成这种问题的根源在于浏览器主线程,它会阻塞我们的JS事件循环,使我们无法在页面加载时进行任何操作。

解决这个问题的一个常见方法是使用Web Workers,它们允许您在后台运行JavaScript代码,而不会阻塞主线程。

另一个解决方案是使用延迟加载,这是一种将数据分成更小的块并在需要时加载它们的技术。这可以减少主线程的负载,并使页面加载更快。

但这些都是基于浏览器本身的层面,我们作为前端开发者,或者说前端优化人员,可以在前面对数据进行一些优化处理,这样可以让浏览器展现出来的加载更加友好,页面更丝滑。

比如,我们假设有20条数据要一次性填充到ul上,此时我们显然不适合这样做:

//假设存在ul元素,此处以伪代码表示
const ul = document.getElementById('list');

//20条数据使用循环的方式生成li并填充进去
for (let i = 0; i < 20; i++) {
  const li = document.createElement('li');
  li.textContent = `我是数据:${i}`;
  ul.appendChild(li);
}

实践上述代码,我们发现界面体验很不友好,卡顿感严重。出现卡顿感的原因在于,循环会一次性将所有的li标签创建出来,并插入到ul中,在这个过程中,浏览器的主线程会处于阻塞状态,导致页面失去响应。

一种优化的方法就是将li元素的创建和插入过程分批次进行,比如:

const ul = document.getElementById('list');

//分批次插入数据,每批次10条数据
const batchSize = 10;
let start = 0;
let end = batchSize;
const timer = setInterval(() => {
  //创建li并插入ul中
  for (let i = start; i < end; i++) {
    const li = document.createElement('li');
    li.textContent = `我是数据:${i}`;
    ul.appendChild(li);
  }
  //更新start和end的值,并判断是否所有数据已经插入
  start += batchSize;
  end += batchSize;
  if (end > 20) {
    clearInterval(timer);
  }
}, 100);

分批次处理的方式,使得浏览器可以有更多的时间去处理其他任务,从而避免卡顿的现象。

在这个示例中,我们每隔100毫秒插入10个li元素,这使得浏览器有足够的时间来处理其他任务,而不会出现卡顿的现象。

最后,值得注意的是,分批次插入数据并不是唯一的解决办法,我们也可以使用其他的技术,比如:

  • 使用虚拟DOM来创建和更新元素,这样可以减少对DOM的操作,从而提高性能。
  • 使用Service Worker来缓存数据,这样可以减少从服务器加载数据的时间,从而提高性能。