真实面经题目 · 原创解析
懒加载和虚拟列表如何优化首屏性能?
懒加载通过延后非首屏图像、组件、路由和数据请求,减少首屏需要下载和执行的资源;虚拟列表通过只渲染视口附近的列表项,减少 DOM 数量、布局计算和绘制成本。两者都能优化首屏,但前提是不要延后首屏核心内容,并要处理占位尺寸、预加载、滚动体验和可访问性。
真实面经题目 · 原创解析
懒加载通过延后非首屏图像、组件、路由和数据请求,减少首屏需要下载和执行的资源;虚拟列表通过只渲染视口附近的列表项,减少 DOM 数量、布局计算和绘制成本。两者都能优化首屏,但前提是不要延后首屏核心内容,并要处理占位尺寸、预加载、滚动体验和可访问性。
懒加载解决的是首屏资源过多的问题:非首屏图像、视频、组件、路由代码、低优先级数据可以等用户接近时再加载,常用 loading=lazy、IntersectionObserver、动态 import、路由级 code splitting。虚拟列表解决的是一次性渲染节点过多的问题:长列表只保留视口范围和少量 overscan 元素,滚动时复用或替换节点,用总高度占位维持滚动条长度。优化首屏时,首屏核心图像、标题、关键 CSS 和必要数据不能懒加载;长列表首屏只渲染可见项,可以显著减少 DOM、样式计算、布局和水合成本。
懒加载的核心是把非关键工作移出首屏关键路径。首屏只需要用户马上能看到和使用的资源,首屏之外的图像、视频、图表、评论、推荐模块、低频弹窗和次级路由可以延后。这样网络层减少初始请求和字节数,主线程减少解析执行,浏览器也少做样式、布局和绘制工作。
图像资源可以使用原生 loading=lazy,也可以用 IntersectionObserver 在元素接近视口时替换真实 src;组件和路由可以用动态 import 按需加载;数据可以在模块进入视口前预取。实际工程中还要设置 width、height 或 aspect-ratio,避免资源加载后撑开布局;对即将进入视口的内容提前加载,避免用户滚动到位置时仍是空白。
虚拟列表针对长列表首屏和滚动性能。假设有一万条数据,页面不需要同时创建一万个 DOM 节点,只需要渲染当前视口能看到的几十条和前后缓冲项。容器用总高度模拟完整滚动范围,内部列表通过 translate 或定位移动到对应位置。这样 DOM 数量稳定,布局和绘制压力与总数据量解耦。
在 SSR 或水合场景中,虚拟列表还可以减少首屏 HTML 大小和 hydration 节点数量;在纯客户端渲染中,它减少初始 createElement、样式计算和布局时间。懒加载减少资源和代码,虚拟列表减少节点和渲染工作,两者组合适合信息流、搜索结果、消息列表、日志列表、商品列表等首屏下方数据很多的页面。
懒加载不能用于首屏 LCP 资源,否则会降低核心内容优先级;虚拟列表不适合节点很少的列表,也会带来动态高度测量、滚动定位、键盘导航、查找、打印、浏览器页内搜索和可访问性问题。工程上要根据列表规模、单项高度稳定性、SEO 需求和交互复杂度判断是否值得引入。
如果首屏最大内容元素被懒加载,浏览器会降低它的发现和加载优先级,导致核心内容更晚出现。首屏关键图像应直接加载,并可通过 preload、fetchpriority、尺寸压缩等方式优化。
它会用总数据量乘以行高,或用动态测量后的累计高度创建一个占位空间。实际渲染的可见项再通过偏移定位到当前滚动位置,因此滚动条看起来对应完整列表。
固定高度可以直接用索引计算偏移;动态高度需要测量每项真实高度并维护累计高度,滚动跳转、快速滚动和数据变化时都要校正偏移,否则容易出现抖动或位置不准。
代码分割把 bundle 拆成多个块,懒加载决定某些块何时加载。路由级或组件级动态 import 可以让首屏只下载必要代码,用户进入对应功能时再加载剩余代码。