图片懒加载


一、介绍

定义:图片懒加载是一种延迟加载非视口(viewport)内图片的技术,当用户滚动到图片位置时才加载资源。

核心目的

  • 减少初始页面加载时间
  • 节省用户带宽
  • 降低服务器压力
  • 提升用户体验(特别是移动端)

应用场景:电商网站、图库、长列表、社交媒体等图片密集型页面。


二、实现方式

1. 传统方案(Scroll Event + 位置计算)
<!-- HTML结构 -->
<img class="lazy" data-src="real-image.jpg" src="placeholder.jpg" />
function lazyLoad() {
  const lazyImages = document.querySelectorAll('.lazy');

  lazyImages.forEach((img) => {
    // 获取图片距离视口顶部的距离
    const rect = img.getBoundingClientRect();
    // 当图片进入视口(+100px预加载区域)
    if (rect.top < window.innerHeight + 100) {
      img.src = img.dataset.src;
      img.classList.remove('lazy');
    }
  });
}

// 使用节流优化滚动事件
window.addEventListener('scroll', throttle(lazyLoad, 200));
window.addEventListener('load', lazyLoad);

// 节流函数实现
function throttle(func, delay) {
  let lastCall = 0;
  return function (...args) {
    const now = new Date().getTime();
    if (now - lastCall < delay) return;
    lastCall = now;
    func.apply(this, args);
  };
}
2. 现代方案(Intersection Observer API - 推荐)
const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        observer.unobserve(img); // 加载后停止观察
      }
    });
  },
  {
    rootMargin: '100px', // 预加载距离
  }
);

document.querySelectorAll('.lazy').forEach((img) => {
  observer.observe(img);
});
3. 兼容性处理
if ('IntersectionObserver' in window) {
  // 使用现代API
} else {
  // 回退到传统方案
  window.addEventListener('scroll', throttle(lazyLoad, 200));
}

三、优缺点对比

优点 缺点
▶️ 提升页面加载速度 50%+ ◼️ 增加代码复杂度
▶️ 减少不必要资源请求 ◼️ 旧浏览器需要兼容处理
▶️ 降低服务器带宽消耗 ◼️ SEO 不友好(需额外处理)
▶️ 改善移动端用户体验 ◼️ 快速滚动可能显示空白

四、面试高频问题

  1. 如何检测图片进入视口?

    • 传统方案:getBoundingClientRect() + window.innerHeight
    • 现代方案:IntersectionObserver(性能更优)
  2. 如何处理滚动性能?

    • 使用节流(throttle)或防抖(debounce)
    • 现代方案中 API 自带性能优化
  3. 占位图方案有哪些?

    • 纯色占位
    • 低分辨率预览图(LQIP)
    • SVG 矢量占位
    • CSS 渐变背景
  4. 如何兼顾 SEO?

    • <noscript> 标签中放置真实图片
    <img class="lazy" data-src="image.jpg" src="placeholder.jpg" />
    <noscript><img src="image.jpg" /></noscript>
    
  5. 预加载边界如何设置?

    • 通过 rootMargin 参数(现代方案)
    • 计算时增加偏移量(传统方案)

五、最佳实践

  1. 优先使用 Intersection Observer

    • 原生支持,性能最优
    • 支持预加载(rootMargin
  2. 响应式图片支持

    <img
      class="lazy"
      data-srcset="small.jpg 480w, large.jpg 1080w"
      data-sizes="auto"
      src="placeholder.jpg"
    />
    
  3. 加载状态反馈

    .lazy {
      background: #f5f5f5;
      transition: opacity 0.3s;
    }
    .lazy.loaded {
      opacity: 1;
    }
    
  4. 错误处理

    img.onerror = function () {
      this.src = 'fallback.jpg';
      this.dataset.error = true;
    };
    
  5. 框架集成方案

    • Vue: vue-lazyload
    • React: react-lazy-load-image-component

六、面试回答策略

  1. 概念清晰化

    “懒加载的核心思想是:按需加载。通过延迟非视口资源的加载,优化关键渲染路径”

  2. 对比分析

    “传统方案需要手动计算位置,而 Intersection Observer 利用浏览器原生能力,性能更好且代码更简洁”

  3. 问题导向

    当被问及性能优化: “在电商项目中,实现懒加载后首屏加载时间减少 40%,Lighthouse 评分提升 30%”

  4. 体现深度

    “我们还需要考虑:加载失败时的降级方案、占位图导致的布局偏移(CLS)优化、以及 SSR 场景下的特殊处理”

  5. 展示扩展知识

    “除了图片,懒加载也适用于:组件按需加载(React.lazy)、数据分页加载、视频资源等场景”

  6. 手写代码提示

    • 先说明实现思路
    • 写核心代码段(不必完整)
    • 强调关键点(节流/Intersection Observer)

💡 面试金句
“懒加载不是单纯的技术实现,而是用户体验与性能的平衡艺术。现代浏览器提供的 Intersection Observer API 让我们能以声明式实现高效延迟加载,同时需要为传统浏览器提供平稳退化方案。”

Copyright © Jun 2025 all right reserved,powered by Gitbook该文件修订时间: 2025-07-03 17:35:08

results matching ""

    No results matching ""

    results matching ""

      No results matching ""