讲到性能优化,经常会提及到图片懒加载。在很多的活动页或者商品展示页中,会存在很多的图片,这些普通大多是网络请求下来的。这里有个问题,一次性下载这么多的图片会很耗时。为了解决这个问题,我们可以考虑只下载当前可视区域的图片,后面的图片等到我们滚动到对应的位置再去加载。这样,图片懒加载的方案就出来了。监听页面滚动,当图片到达了可视区域,再去请求。下面我们来实现一下:

var imgs = document.querySelectorAll('img');
addEventListener(
'scroll',
imgs.forEach((img) => {
if (
!img.src &&
img.getBoundingClientRect().top < document.documentElement.clientHeight
) {
img.src = img.dataset.src;
}
})
);

以上 demo 在一开始并没有设置 src 属性,因为设置了就会被请求。而是先设置 dataset.src, 到了视口之后再设置 src 属性,这样就可以达到懒加载的目的了。

但是,上面的 demo 是有点小问题的,用户的每一次滚动都会触发一下这个回调函数。若用户疯狂的滚动,就会不断的调用这个函数,会很消耗资源。为了解决这个问题,我们可以写一个节流函数,在指定的时间内只执行一次这个回调函数。再来看一下改进版的懒加载 demo:

var imgs = document.querySelectorAll('img');
function throttle(fn, threshhold) {
var timeout;
var start = new Date();
var threshhold = threshhold || 160;
return function () {
var context = this,
args = arguments,
curr = new Date() - 0;

clearTimeout(timeout);
if (curr - start >= threshhold) {
fn.apply(context, args);
start = curr;
} else {
timeout = setTimeout(function () {
fn.apply(context, args);
}, threshhold);
}
};
}
addEventListener(
'scroll',
throttle((e) => {
imgs.forEach((img) => {
if (
!img.src &&
img.getBoundingClientRect().top < document.documentElement.clientHeight
) {
img.src = img.dataset.src;
}
});
}, 1000)
);