原生 lazy 加载对比 JS 监听滚动实现性能区别?

文章导读
优先使用浏览器原生的 loading="lazy" 属性,除非你需要兼容 2019 年之前的旧浏览器或需要复杂的加载状态控制,否则不建议手动写 JS 监听滚动。
📋 目录
  1. A 性能差异本质与测试方法
  2. B 浏览器兼容性对照表
  3. C 落地实施步骤
  4. D 效果验证方法
  5. E 常见坑与排查
  6. F 参考资料
A A

优先使用浏览器原生的 loading="lazy" 属性,除非你需要兼容 2019 年之前的旧浏览器或需要复杂的加载状态控制,否则不建议手动写 JS 监听滚动。

先说结论:原生方案由浏览器内核直接处理,性能开销更低且代码极简,JS 方案仅在需要兼容旧环境或自定义复杂逻辑时使用。

  • 适合:标准图片、iframe 延迟加载,且目标用户浏览器支持原生特性。
  • 重点看:浏览器兼容性差异,特别是 Safari 15.4 以下版本需要降级处理。
  • 别忽略:无论哪种方案,都必须设置图片宽高以避免布局偏移(CLS)。

性能差异本质与测试方法

标题提到的性能区别主要源于执行机制的不同。原生懒加载是浏览器渲染流水线的一部分,运行在合成器线程,不占用主线程资源。传统的 JS 滚动监听需要监听 scroll 事件,该事件触发频率极高,即使做了节流(throttle)处理,仍然会占用主线程资源,可能导致滚动卡顿。

虽然具体性能数据依赖硬件环境,但可以通过以下方法在本地验证差异:

  1. 打开 Performance 面板:在 Chrome DevTools 中录制滚动过程。
  2. 观察 Main 线程:JS 监听方案会看到大量的黄色事件块(Scripting)和绿色事件块(Rendering),而原生方案主线程几乎无额外开销。
  3. 对比 FPS:在低端设备上快速滚动长列表,JS 方案容易出现 FPS 波动,原生方案通常能保持稳定的 60FPS。

Intersection Observer API 虽然也是 JS 方案,但它由浏览器异步通知元素可见性变化,避免了频繁计算元素位置,性能远优于传统滚动监听,但仍不及原生属性高效。

浏览器兼容性对照表

在决定方案前,请根据用户群体核对以下兼容性数据。不支持原生的环境需执行降级策略。

原生 lazy 加载对比 JS 监听滚动实现性能区别?
浏览器最低支持版本备注
Chrome76+Android Chrome 同样支持
Firefox75+桌面与移动端均支持
Safari15.4+iOS 15.4+ 是关键分水岭
Edge79+基于 Chromium 内核
Opera64+基于 Chromium 内核

落地实施步骤

1. 启用原生懒加载
在所有 img 标签中添加 loading="lazy"。确保真实图片地址在 src 中,浏览器会自动处理加载时机。

<img src="image.jpg" loading="lazy" alt="描述" width="800" height="600">

2. 设置尺寸占位
无论使用哪种方案,都必须显式设置 width 和 height,或使用 aspect-ratio,防止图片加载时页面跳动。

<img src="image.jpg" loading="lazy" width="800" height="600" style="aspect-ratio: 4/3;">

3. 添加降级方案
检测浏览器是否支持原生属性,不支持则动态加载 Intersection Observer 脚本或 polyfill。注意不要重复绑定事件。

if ('loading' in HTMLImageElement.prototype) {\n  // 支持原生,无需操作\n  const images = document.querySelectorAll('img[loading="lazy"]');\n  console.log('Native lazy loading supported', images.length);\n} else {\n  // 不支持原生,加载 JS 懒加载库\n  const script = document.createElement('script');\n  script.src = 'path/to/lazyload-polyfill.js';\n  document.body.appendChild(script);\n}

效果验证方法

1. 网络面板观察
打开浏览器开发者工具的 Network 面板,刷新页面后缓慢滚动。原生方案下,屏幕外的图片请求状态应显示为 pending 或未发起,进入视口后才变为 200。注意清除缓存测试。

2. 性能评分检查
使用 Lighthouse 跑分,关注 Largest Contentful Paint (LCP) 和 Cumulative Layout Shift (CLS) 指标。确保懒加载没有导致核心内容加载延迟或页面跳动。CLS 分数应低于 0.1。

原生 lazy 加载对比 JS 监听滚动实现性能区别?

3. 内存占用监控
在 Performance Monitor 面板观察 JS Heap 大小。JS 监听方案在长列表场景下,若未正确销毁 observer,内存可能持续上升。

常见坑与排查

1. 兼容性盲区
Safari 15.4 以下版本完全不支持 loading="lazy",iOS 用户占比高时需特别注意。可通过 User-Agent 判断或统一使用 JS 方案兜底。

2. 布局偏移 (CLS)
未设置图片宽高会导致图片加载后撑开容器,引起页面抖动,严重影响用户体验和性能评分。务必预留空间。

3. 错误处理缺失
原生方案不支持自定义加载失败后的重试或占位图逻辑,关键业务图片建议保留 JS 方案以便处理 onerror 事件。

4. 容器高度为 0
如果图片父容器高度由图片本身撑开,懒加载初期容器高度可能为 0,导致后续元素上移。建议使用固定宽高比容器。

参考资料

  • MDN Web Docs: <img> loading attribute
  • Can I use: loading attribute for img elements
  • Google Developers: Native image lazy-loading for the web
  • Web.dev: Improve CLS with size attributes