Interview AiBoxInterview AiBox 实时 AI 助手,让你自信应答每一场面试
请解释图片懒加载的原理和实现方式
题型摘要
图片懒加载是一种延迟加载非可视区域图片的性能优化技术。主要实现方式有四种:基于滚动事件监听(兼容性好但性能差)、基于Intersection Observer API(现代高效方式)、使用loading属性(原生支持,最简单)以及第三方库(功能丰富)。最佳实践是优先使用原生懒加载,必要时结合Intersection Observer API,并添加占位图和提前加载以提升用户体验。
图片懒加载的原理和实现方式
定义与原理
图片懒加载(Lazy Loading)是一种网页性能优化技术,它延迟加载页面中非可视区域的图片,只有当图片即将进入用户可视区域时才进行加载。这样可以减少初始页面加载时间、降低服务器负载和节省带宽。
为什么需要图片懒加载
- 提升页面加载速度:只加载可视区域内的图片,减少初始HTTP请求数量
- 节省带宽资源:用户可能不会滚动到页面底部,不必要加载所有图片
- 提升用户体验:页面可以更快地呈现主要内容,减少用户等待时间
- 减轻服务器压力:减少不必要的图片请求,降低服务器负载
实现方式
1. 基于滚动事件监听
原理:
- 给图片设置一个自定义属性(如
data-src)存储真实图片地址,src属性可以设置为空或占位图 - 监听滚动事件,计算每个图片元素的位置与可视区域的关系
- 当图片进入可视区域时,将
data-src的值赋给src属性,触发图片加载
代码示例:
document.addEventListener("DOMContentLoaded", function() {
let lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
if ("IntersectionObserver" in window) {
// 如果浏览器支持Intersection Observer,使用更高效的方式
} else {
// 回退到滚动事件监听方式
let active = false;
const lazyLoad = function() {
if (active === false) {
active = true;
setTimeout(function() {
lazyImages.forEach(function(lazyImage) {
if ((lazyImage.getBoundingClientRect().top <= window.innerHeight && lazyImage.getBoundingClientRect().bottom >= 0) && getComputedStyle(lazyImage).display !== "none") {
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove("lazy");
lazyImages = lazyImages.filter(function(image) {
return image !== lazyImage;
});
if (lazyImages.length === 0) {
document.removeEventListener("scroll", lazyLoad);
window.removeEventListener("resize", lazyLoad);
window.removeEventListener("orientationchange", lazyLoad);
}
}
});
active = false;
}, 200);
}
};
document.addEventListener("scroll", lazyLoad);
window.addEventListener("resize", lazyLoad);
window.addEventListener("orientationchange", lazyLoad);
lazyLoad();
}
});
优点:
- 兼容性好,支持所有主流浏览器
- 实现简单直观
缺点:
- 滚动事件频繁触发,性能较差
- 需要手动计算元素位置,代码复杂
- 滚动事件处理函数需要做节流处理,否则会影响性能
2. 基于Intersection Observer API
Intersection Observer API是现代浏览器提供的一种异步检测目标元素与祖先元素或视口相交情况的方法。它是实现懒加载的更高效方式。
原理:
- 创建一个Intersection Observer实例,配置回调函数和选项
- 观察所有需要懒加载的图片元素
- 当图片元素进入可视区域时,触发回调函数,加载图片
代码示例:
document.addEventListener("DOMContentLoaded", function() {
var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
if ("IntersectionObserver" in window) {
let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
let lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove("lazy");
lazyImageObserver.unobserve(lazyImage);
}
});
}, {
rootMargin: "0px 0px 200px 0px" // 提前200px加载
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
} else {
// 回退到滚动事件监听方式
}
});
优点:
- 性能更好,由浏览器内部优化,不依赖主线程
- 代码更简洁,不需要手动计算元素位置
- 可以配置提前加载的距离(rootMargin)
- 不需要节流处理
缺点:
- 不支持旧版浏览器(如IE)
- 需要添加polyfill以支持更多浏览器
3. 使用loading属性(原生懒加载)
现代浏览器(Chrome 76+、Firefox 75+、Edge 79+)支持原生的图片懒加载,只需给<img>标签添加loading="lazy"属性。
原理:
- 浏览器原生支持,无需JavaScript
- 浏览器自动判断图片是否进入可视区域,并决定何时加载
代码示例:
<img src="image.jpg" loading="lazy" alt="..." width="200" height="200">
优点:
- 实现最简单,只需添加一个属性
- 性能最好,由浏览器内部优化
- 无需额外JavaScript代码
缺点:
- 浏览器支持有限,不兼容所有浏览器
- 可定制性差,无法控制加载时机和提前加载的距离
4. 使用第三方库
有许多成熟的第三方库可以实现图片懒加载,如:
- lozad.js
- lazysizes
- yall.js
- Echo.js
原理:
- 这些库封装了懒加载的逻辑,通常基于Intersection Observer API或滚动事件
- 提供更多功能和配置选项
代码示例(以lozad.js为例):
<!-- 引入lozad.js -->
<script src="https://cdn.jsdelivr.net/npm/lozad/dist/lozad.min.js"></script>
<!-- HTML -->
<img class="lozad" data-src="image.jpg" alt="...">
<!-- JavaScript -->
<script>
const observer = lozad(); // 默认配置
observer.observe();
</script>
优点:
- 功能丰富,通常提供更多配置选项
- 已经处理了各种边界情况和兼容性问题
- 可能包含额外功能,如占位图、加载动画等
缺点:
- 增加项目依赖和体积
- 可能包含不需要的功能
实现方式对比
| 实现方式 | 兼容性 | 性能 | 实现难度 | 可定制性 |
|---|---|---|---|---|
| 滚动事件监听 | 高 | 差 | 中 | 高 |
| Intersection Observer API | 中 | 高 | 低 | 高 |
| loading属性 | 低 | 最高 | 最低 | 低 |
| 第三方库 | 高 | 中高 | 最低 | 中高 |
最佳实践
- 优先使用原生懒加载:如果不需要支持旧浏览器,优先使用
loading="lazy"属性 - 使用Intersection Observer API:需要兼容更多浏览器时,使用Intersection Observer API,并提供滚动事件监听作为回退方案
- 考虑使用第三方库:如果项目需要更多功能或不想处理实现细节,可以使用成熟的第三方库
- 添加占位图:为未加载的图片添加占位图或背景色,避免页面布局跳动
- 提前加载:设置适当的提前加载距离,提升用户体验
- 考虑图片格式:使用现代图片格式如WebP,减少图片体积
- 响应式图片:结合
srcset和sizes属性,为不同设备提供适当大小的图片
思维导图
Interview AiBoxInterview AiBox — 面试搭档
不只是准备,更是实时陪练
Interview AiBox 在面试过程中提供实时屏幕提示、AI 模拟面试和智能复盘,让你每一次回答都更有信心。
AI 助读
一键发送到常用 AI
图片懒加载是一种延迟加载非可视区域图片的性能优化技术。主要实现方式有四种:基于滚动事件监听(兼容性好但性能差)、基于Intersection Observer API(现代高效方式)、使用loading属性(原生支持,最简单)以及第三方库(功能丰富)。最佳实践是优先使用原生懒加载,必要时结合Intersection Observer API,并添加占位图和提前加载以提升用户体验。
智能总结
深度解读
考点定位
思路启发
相关题目
在项目中做了哪些性能优化?
前端性能优化主要包括:1)加载性能优化(代码分割、懒加载、预加载、缓存策略);2)渲染性能优化(减少重排重绘、虚拟列表);3)资源优化(图片优化、资源压缩合并);4)代码优化(防抖节流、React组件优化);5)用户体验优化(骨架屏、渐进式增强);6)性能监控与分析(核心Web指标、性能分析工具)。通过这些优化,可显著提升首屏加载速度、交互响应时间和核心Web指标。
请谈谈前端性能优化的方法和策略。
前端性能优化是提升用户体验的关键,包括资源加载优化、渲染优化、代码执行优化、构建打包优化和性能监控分析五大方面。资源加载优化关注减少请求、使用CDN、压缩资源、预加载和缓存策略;渲染优化聚焦于关键渲染路径、避免布局抖动、减少重绘重排和使用硬件加速;代码执行优化涉及JavaScript和CSS优化及Web Worker使用;构建打包优化包括代码分割、Tree Shaking和压缩混淆;性能监控则通过API、Lighthouse和Web Vitals实现持续优化。
在前端开发中,你了解并实践过哪些性能优化方法?请从网络加载、渲染性能、代码优化等方面进行阐述。
前端性能优化是提升用户体验的关键环节,主要从三个方面进行:网络加载优化、渲染性能优化和代码优化。网络加载优化包括资源压缩与合并、使用CDN、缓存策略、图片优化、按需加载、预加载与预连接、HTTP/2或HTTP/3等技术。渲染性能优化包括减少重排与重绘、使用requestAnimationFrame、优化CSS选择器、避免强制同步布局、虚拟列表、Web Workers和CSS Containment等方法。代码优化包括算法与数据结构优化、事件委托、防抖与节流、避免内存泄漏、使用性能API、Tree Shaking和代码分割等技术。此外,还可以通过使用现代前端框架、WebAssembly、服务端渲染与静态站点生成、性能监控与分析、骨架屏与加载状态等策略进一步提升性能。实施前端性能优化需要系统性思考,建立性能指标,持续监控,针对性优化,并在性能与开发效率间取得平衡。
请比较Vite和Webpack的区别
Vite和Webpack是两种流行的前端构建工具,各有特点。Webpack是成熟稳定的模块打包器,通过loader和plugin处理各种资源,配置灵活但复杂,适合大型复杂项目。Vite是新一代构建工具,利用浏览器原生ESM支持,开发环境启动和热更新极快,配置简洁,适合中小型项目和现代浏览器环境。在生产构建方面,Webpack经过多年优化更成熟,而Vite使用Rollup进行打包。两者在生态系统、插件开发、适用场景等方面也有差异。选择应基于项目需求、团队技术栈和目标环境等因素考虑。
请谈谈前端性能优化的方法和策略
前端性能优化是提升网页加载速度、响应速度和运行效率的关键过程。主要优化方向包括:网络传输优化(减少HTTP请求、使用CDN、启用压缩、缓存策略)、资源加载优化(关键渲染路径优化、预加载与预获取、懒加载)、渲染性能优化(减少重排重绘、优化动画、优化大型列表)、JavaScript执行优化(减少主线程阻塞、优化事件处理、优化算法)、CSS优化(减少复杂度、优化文件、使用高效属性)、图片优化(选择合适格式、压缩优化、懒加载占位)以及性能监控与分析。通过系统性的优化策略和持续监控,可以显著提升用户体验。