面试题:前端web页面性能如何优化

0 阅读11分钟

面试题:前端web页面性能如何优化

整体思路:指标->思路->具体策略

一、核心性能指标

github.com/GoogleChrom…

LCP 最大内容绘制

  • 衡量:首屏加载速度
  • 定义:页面从加载到视口内最大内容渲染完成的时间
  • 标准:≤ 2.5s 良好

INP 交互下一次绘制

  • 衡量:页面交互响应速度
  • 定义:用户所有点击、输入、触摸操作的最大响应延迟
  • 标准:≤ 200ms 良好

CLS 累积布局偏移

  • 衡量:页面视觉稳定性
  • 定义:页面非用户主动触发的意外布局抖动总分

juejin.cn/post/743144…

二、具体策略

模块一:网络加载层优化(ROI最高,面试优先讲,80%的性能问题都在这里)

核心目标:减少请求体积、减少请求数量、缩短请求耗时、控制资源加载优先级

1. HTTP协议与请求优化
  • 涉及核心知识点:HTTP1.1/HTTP2/HTTP3特性、TCP三次握手/慢启动、队头阻塞、CDN原理、同源策略、DNS解析

  • 面试落地

    • 协议升级:优先升级HTTP2/HTTP3,解决HTTP1.1队头阻塞问题,利用多路复用、头部压缩、服务端推送能力,大幅降低请求耗时

    • CDN全量部署:静态资源(JS/CSS/图片/字体)全量接入CDN;静态资源与主页面域名拆分,避免请求携带cookie(因为没用),同时减少DNS解析开销

    • 减少无效请求:小资源内联(≤10KB的图片转base64、小体积JS/CSS内联到HTML),避免发起单独请求;注意这里H1和H2 相反。H2多些利用多路复用好,H1请求多会阻塞。

    • 预连接优化:对跨域CDN/接口域名,通过preconnect提前建立TCP连接,dns-prefetch提前完成DNS解析,减少后续请求的RTT耗时 juejin.cn/post/691520…

2. 资源体积压缩优化
  • 涉及核心知识点:Gzip/Brotli压缩原理、文本编码、字符集优化

  • 面试落地实现

    • 服务端开启压缩:Nginx/Node服务优先开启Brotli压缩(比Gzip压缩率高15%-20%),降级兼容Gzip,覆盖HTML/JS/CSS/JSON等所有文本资源

    • 代码压缩:生产环境通过工具剔除注释、空格、变量名混淆,移除debugger、console.log等调试代码,剔除无用的死代码

    • 字体优化:使用WOFF2格式(兼容性好、体积最小),通过字体子集化只打包项目用到的字符;设置font-display: swap避免字体加载阻塞渲染和布局偏移

3. 图片资源优化
  • 涉及核心知识点:图片格式编码原理、响应式图片、懒加载原理、浏览器图片解码机制、渐进式加载

  • 面试落地实现

    • 格式选型:优先使用AVIF/WebP格式(比JPG/PNG体积小50%以上),通过picture标签做降级兼容;图标优先使用SVG/字体图标,替代位图

    • 压缩处理:生产环境禁止原图直出,通过工具做无损/有损压缩,剔除图片EXIF信息,平衡画质与体积

    • 响应式加载:通过srcset + sizes/picture标签,根据设备分辨率、屏幕尺寸加载对应尺寸的图片,避免大图加载到小屏设备造成的带宽浪费

    • 加载策略:首屏可视区图片优先加载,非首屏图片使用原生loading="lazy"懒加载;大图片使用渐进式加载,背景图通过image-set适配不同设备

    • 进阶优化:接入图片CDN,通过URL参数动态调整图片的尺寸、格式、质量,实现按需加载

4. 资源加载优先级控制
  • 涉及核心知识点:浏览器资源加载优先级、preload/prefetch原理、async/defer区别、渲染阻塞机制

  • 面试落地实现(可直接说)

    • 关键资源预加载:首屏必需的核心JS/CSS/字体,通过preload提前加载,提升加载优先级;非首屏、后续页面可能用到的资源,通过prefetch在浏览器空闲时预加载

    • 脚本加载优化:渲染阻塞的JS脚本,根据场景使用defer(DOM解析完成后顺序执行,适合有依赖的脚本)/async(下载完成后立即执行,适合无依赖的第三方脚本);非关键脚本异步加载,避免阻塞主线程

    • 资源加载顺序:CSS放在head标签,JS放在body底部,避免阻塞DOM和CSSOM构建


模块二:缓存策略优化

核心目标:复用已加载资源,减少重复请求,提升二次/多次访问的性能

1. HTTP缓存优化
  • 涉及核心知识点:强缓存/协商缓存原理、缓存优先级、Cache-Control、ETag/Last-Modified

  • 面试落地实现

    • 强缓存:通过Cache-Control设置,配合哈希文件名,内容变更时哈希变化自动触发更新;禁止缓存的内容设置no-store

    • 协商缓存(发起请求验证资源是否过期,未过期返回304,不返回资源体):经常变动的资源(HTML/接口数据)设置Cache-Control: no-cache,强制走协商缓存;优先使用ETag/If-None-Match,降级兼容Last-Modified/If-Modified-Since

    • 缓存分层:CDN缓存+浏览器缓存双层策略,静态资源预热CDN,提升边缘节点命中率

2. 本地存储与进阶缓存
  • 涉及核心知识点:localStorage/sessionStorage/IndexedDB区别、Service Worker生命周期、PWA缓存策略

  • 面试落地实现

    • 浏览器本地存储:不敏感、不常变动的接口数据、配置信息,存入localStorage,减少重复请求;大量结构化数据使用IndexedDB存储;会话级数据使用sessionStorage

    • Service Worker + PWA:通过Workbox快速接入Service Worker,拦截网络请求,自定义缓存策略;静态资源使用「缓存优先」策略,接口数据使用「 stale-while-revalidate(先返回缓存,异步更新)」策略,实现离线可用、二次访问秒开 juejin.cn/post/715165…


模块三:渲染解析层优化

核心目标:加快首屏渲染、减少重排重绘、降低布局偏移、提升渲染流畅度

  • 涉及核心知识点:浏览器渲染流水线、重排(Reflow)/重绘(Repaint)/合成层(Composite)原理、GPU加速、CSS选择器匹配规则、SSR/SSG原理
面试落地实现
  1. 关键渲染路径优化

    1. 禁止在CSS中使用@import,会导致CSS串行加载,延长渲染阻塞时间
  2. 重排重绘优化

    1. 批量修改DOM:先将DOM脱离文档流(display: none),修改完成后再放回文档,避免多次触发重排
    2. 读写分离:避免DOM属性的读写交替,触发强制同步布局
    3. 动画优化:使用transform/opacity实现动画,只会触发合成层,不会重排重绘;通过will-change: transform将动画元素提升到独立合成层,开启GPU加速,禁止使用margin/top/left做动画
  3. 视觉稳定性优化

    1. 图片/视频/iframe提前设置宽高,避免加载后撑开布局;动态插入的内容提前预留占位容器
    2. 禁止在视口顶部插入DOM元素;广告位、动态内容提前固定尺寸,避免加载后页面抖动
    3. 字体加载设置font-display: swap,避免字体闪烁导致的布局偏移
  4. DOM优化

    1. 缓存DOM节点查询结果,避免多次执行querySelector等DOM查询操作
    2. 批量插入DOM使用DocumentFragment,避免每次插入都触发重排
    3. 减少DOM节点总数,避免嵌套层级过深;非可视区内容使用懒渲染/虚拟滚动,只渲染可视区DOM
    4. 使用事件委托,将多个子元素的事件监听委托到父元素,减少事件监听数量,降低内存占用
  5. 首屏渲染进阶优化

    1. 渲染方案选型:首屏要求高的页面,使用SSR(服务端渲染)/SSG(静态站点生成),直接返回带内容的HTML,减少客户端渲染的白屏时间,大幅提升LCP/FCP

    2. 骨架屏/占位图:首屏加载时先渲染骨架屏,提升用户体感,同时避免布局偏移

    3. SPA静态页面使用预渲染,构建时生成对应HTML,提升首屏渲染速度


模块四:JavaScript执行优化

核心目标:减少JS包体积、降低JS执行耗时、避免长任务阻塞主线程、解决内存泄漏、提升交互响应速度

  • 涉及核心知识点:JS事件循环、宏任务/微任务、调用栈、垃圾回收(GC)机制、长任务、内存泄漏原理、框架响应式与Diff算法原理
1. JS包体积优化
  • 面试落地实现

    • 代码分割(Code Splitting):通过动态import()实现路由懒加载,将JS包拆分为多个chunk,首屏只加载必需的chunk,非首屏路由按需加载;第三方库单独拆包,利用浏览器缓存

    • Tree Shaking:生产环境开启,移除未使用的死代码;使用ESModule规范,避免CommonJS导致Tree Shaking失效

    • 第三方库优化:大体积库替换(Moment.js→day.js,全量lodash→lodash-es按需引入);UI组件库(Element/AntD)按需引入,禁止全量打包;不常更新的大库通过Externals+CDN引入,不打包进bundle

    • Polyfill优化:通过browserslist设置目标浏览器,只对目标浏览器做语法降级,避免过度polyfill;core-js按需引入,减少冗余代码

2. JS执行性能优化
  • 面试落地实现

    • 避免长任务阻塞主线程:执行时间超过50ms的长任务会阻塞渲染和交互,将长任务拆分为多个小任务,通过requestIdleCallback/requestAnimationFrame分批执行;大数据计算、文件解析等耗时逻辑,放到Web Worker中执行,不占用主线程

    • 减少重复计算:通过memoization缓存重复执行函数的结果;避免循环内执行DOM操作、DOM属性查询等耗时逻辑

    • 高频事件优化:对scroll、resize、input、mousemove等高频触发的事件,做防抖(Debounce)/节流(Throttle)处理,减少函数执行次数

3. 框架专属优化
框架核心知识点面试落地实现配套工具
ReactFiber架构、Diff算法、重渲染原理、memo/useMemo/useCallback1. 使用React.memo包裹纯组件,缓存渲染结果;useMemo缓存计算结果,useCallback缓存函数引用,避免子组件无效重渲染
2. React.lazy + Suspense实现路由懒加载
3. 长列表使用react-window/react-virtualized实现虚拟列表
4. 拆分全局状态,避免无关状态更新导致的全量重渲染
React DevTools(查看组件重渲染)、Performance面板
Vue响应式原理、虚拟DOM、Diff算法、v-if/v-show区别、keep-alive1. 频繁切换的元素用v-show替代v-if,减少DOM销毁重建;v-for必须加唯一key,禁止用index作为key;v-once缓存静态内容
2. 动态import实现路由懒加载
3. 长列表使用vue-virtual-scroller实现虚拟列表
4. keep-alive包裹频繁切换的组件,缓存组件实例
5. 状态模块化拆分,避免全量更新
Vue DevTools(查看组件更新)、Performance面板
4. 内存泄漏优化
  • 面试落地实现

    • 及时清理副作用:组件卸载时,清除定时器、移除事件监听、取消axios请求、解绑订阅事件(EventBus/发布订阅)

    • 避免闭包滥用:闭包会导致变量无法被垃圾回收,及时释放闭包引用

    • 避免全局变量滥用:未声明的变量会成为全局变量,无法被GC回收

    • 避免DOM引用泄漏:缓存的DOM节点,在DOM移除后及时释放引用,避免DOM无法被回收

模块五:工程化与监控体系优化

1. 工程化构建优化
  • 核心知识点:构建工具原理、模块化规范、持久化缓存、多进程构建

  • 落地实现

    • 构建工具选型:优先使用Vite/Rspack等现代构建工具,替代webpack,大幅提升构建速度,同时内置大量优化能力

    • webpack构建优化:通过thread-loader开启多进程构建,提升loader执行速度;开启babel-loader缓存、webpack持久化缓存,提升二次构建速度;配置include/exclude,缩小loader处理范围

    • 性能门禁:CI/CD流程中集成Lighthouse CI,设置性能阈值,指标不达标禁止代码合并,从流程上把控性能

2. 性能监控体系
  • 核心知识点:Performance API、Web Vitals API、用户体验监控、APM系统

  • 落地实现

    • 指标采集:通过浏览器原生API,采集页面核心性能指标、异常数据、用户交互数据
    • 上报与分析:将指标上报到监控平台,统计P75/P90/P95分位值(而非平均值),贴合真实用户体验
    • 告警机制:设置性能阈值,指标超标时触发告警,及时定位线上问题