前端性能优化:懒加载最佳实践

前言

懒加载不是什么新技术,但很多人还是用错了!懒加载能显著减少首屏加载时间,但如果实现不当,反而会影响用户体验。今天我就来给大家讲讲懒加载的最佳实践。

什么是懒加载

懒加载是一种延迟加载技术,只在资源需要时才加载,而不是页面加载时全部加载。

为什么需要懒加载

  • 减少首屏资源体积:只加载首屏需要的资源
  • 提升首屏加载速度:减少HTTP请求数量
  • 节省带宽:用户可能不会滚动到页面底部
  • 提升用户体验:更快的首屏加载

懒加载实现方式

1. 原生懒加载

<!-- 图片懒加载 -->
<img 
  src="placeholder.jpg"
  data-src="image.jpg"
  loading="lazy"
  alt="Lazy loaded image"
>

<!-- iframe懒加载 -->
<iframe 
  src="video-player.html"
  loading="lazy"
></iframe>

2. Intersection Observer API

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const img = entry.target;
      const src = img.getAttribute('data-src');
      img.setAttribute('src', src);
      observer.unobserve(img);
    }
  });
}, {
  rootMargin: '100px 0px',
  threshold: 0.1
});

// 观察所有需要懒加载的图片
document.querySelectorAll('img[data-src]').forEach((img) => {
  observer.observe(img);
});

3. 基于滚动事件

// 传统方式:监听scroll事件
function lazyLoad() {
  const images = document.querySelectorAll('img[data-src]');
  
  images.forEach((img) => {
    const rect = img.getBoundingClientRect();
    const windowHeight = window.innerHeight;
    
    if (rect.top < windowHeight && rect.bottom > 0) {
      const src = img.getAttribute('data-src');
      img.setAttribute('src', src);
      img.removeAttribute('data-src');
    }
  });
}

// 监听滚动事件
window.addEventListener('scroll', lazyLoad);
lazyLoad(); // 初始检查

4. 图片占位符

// 使用SVG占位符
const placeholder = `data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300"%3E%3Crect fill="%23f0f0f0" width="400" height="300"/%3E%3C/svg%3E`;

// 使用低质量占位图(LQIP)
const lqip = 'data:image/jpeg;base64,/9j/4AAQSkZJRg...';

懒加载最佳实践

1. 设置合适的阈值

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      // 加载资源
    }
  });
}, {
  rootMargin: '200px 0px', // 在元素进入视口前200px开始加载
  threshold: 0.1
});

2. 使用渐进式加载

<!-- 先加载低质量图片,再加载高质量图片 -->
<img 
  src="low-quality.jpg"
  data-src="high-quality.jpg"
  class="lazy"
  alt="Progressive image"
>

3. 处理边缘情况

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const img = entry.target;
      const src = img.getAttribute('data-src');
      
      // 添加加载失败处理
      img.onerror = () => {
        img.src = 'fallback.jpg';
      };
      
      img.setAttribute('src', src);
      observer.unobserve(img);
    }
  });
});

4. 懒加载背景图片

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const element = entry.target;
      const bgSrc = element.getAttribute('data-bg');
      element.style.backgroundImage = `url(${bgSrc})`;
      element.removeAttribute('data-bg');
      observer.unobserve(element);
    }
  });
});

// 观察带有data-bg属性的元素
document.querySelectorAll('[data-bg]').forEach((el) => {
  observer.observe(el);
});

懒加载工具库

lazysizes

<script src="lazysizes.min.js"></script>
<img data-src="image.jpg" class="lazyload" alt="Image">

lozad.js

import lozad from 'lozad';

const observer = lozad('.lozad', {
  loaded: (el) => {
    el.classList.add('loaded');
  }
});

observer.observe();

性能监控

// 监控懒加载性能
const startTime = performance.now();

const img = new Image();
img.onload = () => {
  const loadTime = performance.now() - startTime;
  console.log(`Image loaded in ${loadTime}ms`);
};
img.src = 'image.jpg';

常见误区

误区1:懒加载首屏图片

错误:首屏图片也使用懒加载

正确:只懒加载首屏以下的图片

误区2:不设置占位符

错误:懒加载时图片位置空白

正确:使用占位符或骨架屏

误区3:忽略SEO

错误:搜索引擎无法抓取懒加载图片

正确:确保图片可以被搜索引擎抓取

总结

懒加载是提升性能的有效手段,但需要正确实现:

  1. 选择合适的实现方式:原生vs自定义
  2. 设置合理的阈值:提前加载,避免用户等待
  3. 处理边缘情况:加载失败、SEO等
  4. 使用成熟的库:lazysizes、lozad.js

记住,懒加载的目标是提升用户体验,而不是制造新的问题。

核心要点

  • 只懒加载非首屏资源
  • 使用Intersection Observer API
  • 设置合适的预加载阈值
  • 提供占位符提升体验

希望这篇文章能帮助你正确实现懒加载!

Logo

更多推荐