面试这样答之图片懒加载

122 阅读4分钟

一文搞懂图片懒加载

在前端性能优化中,图片往往是“页面加载慢”的罪魁祸首。
图片懒加载(Lazy Load)很好地解决了这个问题,它是一种按需加载资源的前端性能优化策略。
简单来说,就是——只加载用户当前可见区域(首屏)内的图片,而屏幕外的图片在用户滚动到时才加载。

一、什么是图片懒加载?

举个例子

假设有一个包含上百张图片的长网页(比如摄影网站),如果一次性全部请求这些图片,会造成以下题:

  1. 首屏加载时间过长:需要一次性加载所有图片;
  2. 占用大量带宽资源
  3. 浪费资源:用户可能根本不滚动到底部。

而懒加载可以有效解决以上问题

二、图片懒加载的原理

懒加载的核心思想是:

“等图片要显示了再加载”

实现步骤如下:

1. 初始状态

  • 图片不直接加载真实资源
  • 使用占位图或留空 src 作为默认展示
  • 真正图片地址存放在 data-src 属性
<img data-src="real.jpg" src="placeholder.jpg" alt="lazy image">

2. 监听页面滚动或可视区域变化

  • 通过IntersectionObserverscroll 事件判断图片是否进入视口。

3.触发加载

  • 一旦图片进入视口,将data-src的值赋给src,浏览器便会发起加载请求。

4.完成替换

  • 图片加载完成后,可移除data-src属性,或添加动画过渡效果。

三、两种常见的实现方式

方法一:IntersectionObserver(推荐)

现代浏览器支持的原生API,性能优秀且使用简单

<img data-src="https://example.com/pic.jpg" alt="lazy" class="lazy">
//获取所有带有.lazy的图片
const imgs=document.querySelectorAll('img.lazy')
//创建IntersectionObserver实例
const observer=new IntersectionObserver((entries,obs)=>{
    entries.forEach(entry=>{
    //判断图片是否进入可视区
        if(entry.isIntersecting){
            const img=entry.target
            //将真实地址赋给src
            img.src=img.dataset.src   
            //移除lazy类
            img.classList.remove('lazy')
            // 6. 加载完成后取消观察,提升性能
            obs.unobserve(img)       
            
        }
    })
})
//监听每张照片
imgs.forEach(item=>observer.observe(img))

优点:

  • 不需要监听滚动事件,性能好;
  • 浏览器原生优化,可节流;
  • 代码简洁;

缺点:

  • 兼容性有限,比如IE不支持,需要polyfill解决。

方法二:scroll+元素位置计算(兼容方案)

//定义懒加载函数
function lazyLoad(){
    //获取所有未加载真实图片的img
    const imgs=document.querySelectorAll('img[data-src]')
    //获取可视区域高度
    const viewHeight=window.innerHeight||document.documentElement.clientHeight
    
    imgs.forEach(img=>{
    //获取元素相对于视口的位置
        const rect=img.getBoundingClientRect()
        //判断图片是否进入可视区
        if(rect.top<viewHeight){
        //赋值真实图片
            img.src=img.dataset.src
            //移除该属性
            img.removeAttribute('data-src')
        }
    })
}
//监听滚动和页面加载
window.addEventListener('scroll',lazyLoad)
window.addEventListener('load',lazyLoad)
//防抖优化
let timer=null
window.addEventListener('scroll',()=>{
    if(timer) clearTimeout(timer)
    timer=setTimeout(lazyLoad,200)
})

缺点:

  • 频繁触发 scroll,性能差;
  • 需手动节流/防抖优化;
  • 代码量多

所以一般建议加一个防抖函数

四、现代浏览器的懒加载属性(最简单)

现在几乎所有现代浏览器都支持:

<img src="image.jpg" loading="lazy" alt="...">

浏览器会自动在图片进入可视区前加载。
✔ 无需 JavaScript
✔ 原生支持
❌ 兼容性仍需注意(部分旧版 Safari)

六、懒加载的实战优化技巧

优化点说明
使用低质量占位图(LQIP)在真实图片加载前显示模糊缩略图,改善视觉体验
添加加载动画图片加载中可显示 loading 效果
图片懒加载 + 骨架屏对于电商/Feed流页面效果更好
CDN + 懒加载进一步减少图片加载延迟

七、懒加载的局限性

  • 影响 SEO(搜索引擎可能抓不到延迟加载的图片)
  • 对首屏图片不应使用懒加载(会增加白屏时间)
  • 对滚动过快的情况,可能出现闪烁(指图片进入视图才发请求,会出现空白或模糊图到清晰图的情况,故需提前预加载)

八、总结

方式原理优点缺点
IntersectionObserver监听元素进入视口性能好、实现简单兼容性略差
scroll + 计算位置手动监听滚动兼容好需节流优化
<img loading="lazy">浏览器原生支持最简单兼容性需检测

最推荐方案:优先使用 <img loading="lazy">, 若需兼容旧浏览器,则采用 IntersectionObserver 作为兜底方案。

九、面试速记模板

图片懒加载是指页面初始只加载首屏需要的图片,其余图片等进入视口再加载,降低首屏加载时间和资源消耗。
实现方法:先给图片占位或空 src,真实地址存 data-src;当图片进入或快要进入视口时,将 data-src 赋值给 src
三种常用方式:

  1. IntersectionObserver 监听可视区
  2. scroll 事件计算位置手动加载(需防抖/节流)
  3. 浏览器原生属性 loading="lazy"
    ⚠️ 首屏图片不宜懒加载,滚动长列表、图集适用。