web前端性能优化

124 阅读8分钟

一、首屏时间/秒开率

1.1 优化思路

  • 首先最重要的,我们需要了解指标是如何度量的,也就是需要了解首屏时间的算法。这里可能不同公司的算法定义不一样。但大概都是页面稳定,填充率达标之类的计算,还会附加一个最长的超时时间兜底。
  • 其次,要建立首屏渲染关键路径。根据页面特点,建立关键路径的观测。

不同的页面关键路径是不一样的,不同的技术实现,也不同。例如SSR,CSR不同。如果在APP容器里,和在浏览器里也不同。 例如:容器内的SSR和CSR:

   SSR: 容器初始化、获取html、解析HTML,首屏渲染
   CSR: 容器初始化、获取html、解析HTML,加载JS、请求参数准备、请求数据、首屏渲染
  • 再次,进行关键路径的时间度量,观测TP90数据在每个阶段花费的时间是多少。叠加优化手段后,便于观测效果。需要在关键路径埋点,计算时间上报,形成数据看板。

笔者在2019年,基于当时的技术,个人经验一个中等复杂度的web页面(非内嵌app)数据上限秒开率在60%~70%左右。

接下来是针对性的做优化,常用的手段:

1.2 常用手段

  1. SSR

效果是最明显的。缺点是占用服务器资源,可交互时间可能晚于csr.

  1. 图片优化
  • img vs backgroud-image 针对首屏图片,建议使用img src的方式,优先加载会让首屏图片时间尽量缩短。首屏图片推荐使用img标签,非首屏图片推荐使用CSS background image,节省流量。

    • img副作用:过多的Img标签,占用了资源可能会导致其他资源TTFB增加。
  • webp : 图片体积更小,加载速度更快。性能优化的高性价比选择。兼容性要格外看待。通常来说使用webp图片后,图片体积有所减少,如果图片位于首屏,那么首屏图片时间会适当降低,但实际使用中还是要根据具体场景,例如图片较多,图片体积较大,那么需要的解码时间会增长,所带来的也许会是更长的首屏时间。

  • 设置了display:none的首屏图片还会影响首屏时间吗?

    • img display:none浏览器会加载图片
    • img display:none sdk算法可能不计入首屏时间
    • img display:none仍然可能影响首屏时间

可能发生在一些场景,例如通过接口请求回来100个图片,折叠后展示前9个。那么其他的可能用了display none隐藏。 建议不要将首屏不需要展示的图片以img src的方式放在dom中。可以通过将图片地址先存起来,在需要展示时(例如点击才显示时)手动把图片url置给img src。 存储方式有很多种,例如放在dom节点上的data-src属性里,或者放在你的页面状态管理的store中,等等。

  • 图片压缩
    • 甚至需要一个图片检测。大图检测工具。这在app容器下低端机,大量的大体积图片甚至会造成app crash。
  • 真的只能用图片吗?是否可以不用图片。
  1. CSS优化

首屏渲染需求、资源体积、缓存策略三者的平衡,优化 CSS 加载的核心是:让首屏必需的 CSS 尽快可用,同时避免不必要的资源阻塞或体积冗余

  • 首屏关键CSSs内联,非首屏CSS 网络加载
  • 消除未使用的css(比较有风险),这在一些迭代很久的项目里尤其明显,大量的未用的css。
  1. js优化
  • 加载顺序:非必要 JS(如广告、统计)延迟加载
  1. 链路优化
    • 例如SSR,数据预取要快,串行改并行,减少链路耗时无论是sql取数还是rpc调用等。
    • 例如CSR,数据请求,通常为http,http常见优化手段等
  2. 资源效率(网络)
  • 减少http请求数量,去除不必要,合并资源请求等
  • 跨域增加耗时
  • 资源体积减小(前面的图片体积,js,css体积减小等)
  • http 1.1 keep alive,复用TCP连接(同一 TCP 连接上串行处理多个请求(必须等前一个请求完成,才能处理下一个))但是有队头阻塞,并发6个的限制
  • cdn 利用缓存
  • http2 多路复用(同一 TCP 连接上并行处理多个请求(请求可交错发送 / 接收,无需等待))无队头阻塞,并发无限制
  • preload
<link rel="preload" href="critical.js" as="script">
  • http的缓存策略
    • 强缓存 Cache Control, Expires(http 1.0)
      • Cache-Control: max-age=31536000:资源有效期为 31536000 秒(1 年),从请求成功时间开始计算。
    • 协商缓存 ETag (需向服务器验证,资源未变则复用缓存)
    • 无缓存
  1. 静态资源(CSS/JS/ 图片 / 字体)

    • 设置长强缓存:Cache-Control: public, max-age=31536000(1 年)。
    • 文件名添加哈希:如style.abc123.css,内容变化时哈希变化,自动失效旧缓存。
  2. HTML 文件

    • 禁用强缓存(Cache-Control: no-cache),依赖协商缓存(ETagLast-Modified),确保用户每次访问都能获取最新的页面结构。
  3. API 数据

    • 短期强缓存:如max-age=60(1 分钟),适合非实时数据(如商品列表)。

    • 配合stale-while-revalidateCache-Control: max-age=60, stale-while-revalidate=30,允许使用过期缓存的同时后台验证更新,平衡实时性和性能。

      1. 避免缓存污染
    • 对无需缓存的资源(如用户个人数据),设置Cache-Control: no-store(不存储任何缓存)。

    • 区分no-cache(需验证后使用)和no-store(完全不缓存)的区别。

二、卡顿

前端卡顿的核心原因是浏览器主线程过载渲染流程阻塞,导致帧率(FPS)低于 60(每帧需在 16.67ms 内完成)。要解决卡顿,需从 “定位问题→针对性优化→验证效果” 三个环节入手,以下是系统的优化思路和落地方案。

一、先理解:卡顿的本质 —— 浏览器渲染机制

前端所有操作(JS 执行、样式计算、布局、绘制)都依赖主线程,若任一环节耗时超过 16.67ms,就会导致 “掉帧”,表现为卡顿。关键渲染路径如下:

  1. JS 执行:处理脚本(如事件回调、数据计算);

  2. 样式计算:解析 CSS,确定每个元素的样式;

  3. 布局(重排 / 回流) :计算元素的位置和尺寸(最耗时);

  4. 绘制:将元素像素化(如颜色、背景);

  5. 合成:将绘制结果合并为图层,显示在屏幕上。

卡顿的根源通常集中在:主线程长任务阻塞频繁重排重绘资源加载延迟内存泄漏

1. 优化主线程阻塞:避免长任务占用主线程
拆分长任务将复杂逻辑拆分为 “微任务” 或 “分批次任务”,避免单次执行耗时过长- 用setTimeout/requestIdleCallback拆分循环(如处理 1000 条数据→每次处理 100 条); - 用Promise/async/await将同步逻辑拆为异步微任务,不阻塞主线程
计算密集型任务移至 Web Worker主线程只负责 UI 交互,复杂计算(如数据筛选、Excel 导出、图表渲染)交给 Worker- 示例:将 “10 万条数据排序” 放在 Worker 中,计算完成后通过postMessage通知主线程; - 注意:Worker 无法操作 DOM,仅处理纯数据计算
避免同步资源请求同步 XHR/fetch 会阻塞主线程,直到请求完成- 替换为异步请求fetch默认异步); - 禁用XMLHttpRequest.open(method, url, false)(第三个参数为 false 即同步)
高频事件防抖 / 节流避免scroll/resize/input/mousemove等高频事件触发过多回调- 防抖(debounce):输入框搜索(停止输入 100ms 后再请求); - 节流(throttle):滚动加载(每 200ms 仅执行一次)
优化 DOM 操作DOM 操作是主线程 “重灾区”,频繁操作会阻塞执行- 批量操作:用DocumentFragment暂存 DOM,最后一次性插入; - 避免循环内读写 DOM:先读取所有 DOM 属性存为变量,再批量修改
2. 减少重排重绘:降低渲染开销
3. 优化资源加载:避免 “加载阻塞渲染”

资源(JS/CSS/ 图片)加载慢会导致主线程无法及时执行交互逻辑,或渲染延迟,间接引发卡顿。

4. 修复内存泄漏:避免 “内存膨胀导致卡顿”

三、工具:定位卡顿问题的关键

  1. Performance 面板:录制页面运行过程,直观查看 “长任务”“掉帧”“重排重绘”:

    • 红色块:长任务(耗时 > 50ms);
    • 帧率曲线:低于 60 的部分即为卡顿区域;
    • 下方 “Main” 线程:展开可查看每个任务的耗时(如 JS 执行、布局、绘制)。
  2. Memory 面板:检测内存泄漏:

    • 录制 “内存时间线”,观察内存占用是否持续上升(无下降趋势即可能泄漏);
    • 用 “堆快照” 对比不同时间点的内存占用,定位未释放的对象。
  3. Lighthouse:生成性能报告,自动检测卡顿相关问题(如长任务、未优化的图片、未清除的定时器)。