关于 high-perf-browser
通过浏览器、协议和网络的运行原理来优化 Web 性能的框架,适用于前端开发者和运维人员,可用于提升加载速度、配置服务器、制定性能预算和诊断问题。
主要功能
- 01网络延迟与握手分析
- 02HTTP/1.1、HTTP/2 和 HTTP/3 指导
- 03关键资源加载策略
- 04浏览器、Service Worker 与 CDN 缓存
- 05Core Web Vitals 优化
- 06WebSocket、SSE 与轮询指导
适用场景
- 01诊断页面加载缓慢和网络握手问题
- 02选择协议并配置资源交付
- 03为静态资源和 API 制定缓存策略
- 04根据真实用户指标改善 LCP、INP 和 CLS
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wondelai/ skills --skill high-perf-browser安装后在 Claude Code 中输入/high-perf-browser确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/caching-strategies.mdcore-web-vitals.mdhttp-protocols.mdnetwork-fundamentals.mdreal-time-communication.mdresource-loading.md详细介绍
高性能浏览器网络框架
一种系统化的 Web 性能优化方法,立足于浏览器、协议和网络的实际工作原理。在构建前端应用、设定性能预算、配置服务端或诊断页面加载缓慢时,运用这些原则。
核心原则
瓶颈在于延迟,而非带宽。 大多数 Web 性能问题源于往返次数过多,而非吞吐量不足。带宽提升 5 倍,收益会逐渐递减;延迟降低 5 倍,则能显著改善用户体验。
基础原理: 每个请求在收到第一个内容字节前,都要经过 DNS 解析、TCP 握手、TLS 协商和 HTTP 交互——每一步都会增加往返延迟。高性能应用会尽量减少往返次数、并行发送请求,并消除不必要的网络跳转。要实现有意义的优化,必须先了解协议栈。
评分
目标:10/10。 根据八项快速诊断是否通过评分,并重点关注实际指标:9-10 = 八项全部通过(四项实际指标均为绿色,此外还要通过内容哈希、HTTP/2+、减少渲染阻塞和压缩);5-6 = 四项实际指标均通过,但传输、缓存或压缩方面有一项或多项未通过;<=3 = 任一实际指标处于红色。务必报告分数、未通过的诊断项,以及每项对应的具体修复方法。
高性能浏览器网络框架
构建快速、可靠的 Web 应用的六个领域:
1. 网络基础
核心概念: 每个 HTTP 请求都会承担延迟开销——DNS 查询、TCP 三次握手和 TLS 协商——之后应用数据才开始传输。减少或消除这些往返,是收益最高的优化方式。
原理: 光速有限:从纽约到伦敦的一个数据包,单程约需 28ms,与带宽无关。这些物理层面的限制无法通过扩充管道解决,只能通过减少往返次数解决。
关键要点:
- TCP 三次握手会在数据传输开始前增加一个完整的 RTT
- TCP 慢启动会将首个往返中的初始吞吐量限制在约 14KB(10 个数据段)——关键资源应控制在此阈值以内
- 升级到 TLS 1.3:握手往返次数减半,并为回访用户提供 0-RTT 恢复
- TCP 中的队头阻塞意味着一个丢失的数据包会阻塞该连接上的所有流
- 带宽时延积会限制在途数据量;高延迟链路无法充分利用带宽
代码应用:
| 场景 | 模式 | 示例 |
|---|---|---|
| 连接预热 | 预先与关键来源建立连接 | <link rel="preconnect" href="https://cdn.example.com"> |
| DNS 预取 | 提前解析第三方域名(节省 20-120ms) | <link rel="dns-prefetch" href="https://analytics.example.com"> |
| TLS 优化 | TLS 1.3 + 会话恢复 | ssl_protocols TLSv1.3; 并使用会话票证 |
| 连接复用 | Keep-Alive 可避免重复握手 | Connection: keep-alive(HTTP/1.1+ 的默认行为) |
在调整服务器或诊断握手延迟时,请参阅 references/network-fundamentals.md——其中包含 TLS 1.2 与 TLS 1.3 的 RTT 完整推导、慢启动加倍表、initcwnd/BDP 计算、OCSP 装订的 Nginx 配置,以及 DNS 缓存层级。
2. HTTP 协议演进
核心概念: HTTP 从简单的请求-响应协议演变为多路复用的二进制系统。选择合适的协议版本并进行正确配置,可以彻底消除多类性能问题。
为何有效: HTTP/1.1 无法进行多路复用,因此需要各种变通方案(域名分片、精灵图、文件合并)。HTTP/2 支持多路复用,但仍受 TCP 队头阻塞影响;HTTP/3(基于 UDP 的 QUIC)则消除了这一问题。每一代协议都消除了一个瓶颈,也让上一代协议的变通方案适得其反。
关键要点:
- HTTP/1.1 每个 TCP 连接只能有一个未完成的请求;浏览器会为每个主机打开 6 个连接作为变通方案
- HTTP/2 可在一个连接上多路复用无限个流,因此域名分片会适得其反
- HTTP/2 中的 HPACK 标头压缩可减少 85-95% 的重复标头开销
- HTTP/3(QUIC)消除了 TCP 队头阻塞,并支持 0-RTT 恢复和连接迁移
- 优先使用
103 Early Hints,而非 HTTP/2 Server Push(后者会过度推送,并且已被广泛弃用) - 连接合并让一个 HTTP/2 连接能够为共享同一证书的多个主机名提供服务
代码应用:
| 场景 | 模式 | 示例 |
|---|---|---|
| HTTP/2 迁移 | 移除 HTTP/1.1 变通方案 | 撤销域名分片、精灵图和文件合并 |
| 103 Early Hints | 在完整响应前发送预加载提示 | 使用 Link: </style.css>; rel=preload 发送 103 |
| QUIC/HTTP/3 | 在 CDN 或源站声明支持 HTTP/3 | Alt-Svc: h3=":443" 标头 |
| 流优先级 | 指示资源的重要性 | CSS 和字体优先级最高;图片优先级较低 |
选择或迁移协议版本时,请参阅 references/http-protocols.md — 其中包含 HTTP/1.1、HTTP/2 和 HTTP/3 的并排对比、逐步取消分片的迁移指南,以及 Server Push 为何不敌 103 Early Hints 的说明。
3. 资源加载与关键渲染路径
核心概念: 浏览器必须先构建 DOM、CSSOM 和渲染树,才能绘制像素:HTML → DOM → CSSOM → 渲染树 → 布局 → 绘制 → 合成。任何阻塞此流程的资源都会延迟首次绘制。
为何有效: CSS 会阻塞渲染(CSSOM 就绪前不会绘制),而 JavaScript 会阻塞解析(<script> 会暂停 DOM 构建,直到脚本下载并执行完毕),因此两者需要采用不同的优化策略。每个阻塞资源都会直接增加首次绘制所需的时间。
关键要点:
async会并行下载并立即执行(适用于独立脚本);defer会并行下载,但在 DOM 解析完成后执行(适用于大多数脚本)<link rel="preload">会立即以高优先级获取关键资源;rel="prefetch"会以低优先级获取可能用于下一次导航的资源- 将首屏 CSS 内联,其余部分异步加载,从而消除阻塞渲染的 CSS 请求
- 字体最多可能阻塞文本渲染 3 秒;使用
font-display: swap
代码应用:
| 场景 | 模式 | 示例 |
|---|---|---|
| 关键 CSS | 在 <head> 中内联首屏样式 | <style>/* critical */</style> + 异步加载完整 CSS |
| 脚本加载 | 默认使用 defer;独立脚本使用 async | <script src="app.js" defer></script> |
| 资源提示 | 预加载关键字体和主视觉图片 | <link rel="preload" href="font.woff2" as="font" crossorigin> |
| 图片优化 | 延迟加载首屏以下图片;使用现代格式 | <img loading="lazy" src="photo.avif" srcset="..."> |
优化首次绘制时,请参阅 references/resource-loading.md — 其中包含精确的 async/defer/module 执行顺序、完整的资源提示决策树,以及图片和字体(font-display、srcset、AVIF)优化指南。
4. 缓存策略
核心概念: 最快的网络请求,就是根本不会发生的请求。通过分层缓存——浏览器内存、磁盘、Service Worker、CDN、源站——消除回访用户的往返请求。
为何有效: Cache-Control 标头会准确告知浏览器和中间层响应的有效时长;带内容哈希的 URL 则让积极的不可变缓存变得安全。每次缓存命中都会省去一次完整的网络往返。
关键见解:
Cache-Control: no-cache仍会缓存,但每次都会重新验证;no-store则从不缓存——不要混淆两者ETag/Last-Modified可启用条件请求(304 Not Modified),跳过响应正文的传输- Service Worker 提供可编程的缓存层,可支持离线使用(优先使用缓存的应用外壳、优先使用网络的动态内容)
- 配置错误的
Vary标头会导致 CDN 缓存污染——向错误的客户端提供错误的编码或格式
代码应用:
| 场景 | 模式 | 示例 |
|---|---|---|
| 静态资源 | 不可变缓存 + 哈希更新 | style.a1b2c3.css 搭配 Cache-Control: max-age=31536000, immutable |
| HTML 文档 | 每次请求都重新验证 | Cache-Control: no-cache 搭配 ETag |
| API 响应 | 短 TTL + 后台刷新 | Cache-Control: max-age=60, stale-while-revalidate=3600 |
| CDN 配置 | 在边缘缓存并正确设置 Vary | Vary: Accept-Encoding, Accept |
设计缓存策略时,请参阅 references/caching-strategies.md——其中介绍了完整的浏览器/SW/CDN/源站层级、可直接复制粘贴的 Service Worker 优先使用缓存与优先使用网络方案,以及会污染 CDN 的 Vary 陷阱。
5. Core Web Vitals 优化
核心概念: Core Web Vitals——LCP、INP、CLS——是 Google 以用户为中心的指标,涵盖加载、交互性和视觉稳定性。它们会影响搜索排名,并反映真实用户体验。
为何有效: 即使 TTFB 很快,如果首屏主图仍然加载缓慢(LCP),或主线程 JavaScript 阻塞交互(INP),也毫无意义——因此服务器端计时可能显示良好,用户却仍在等待。应优化用户感知到的关键节点,而不是字节传输计时。
关键见解(数值通过/失败阈值见“快速诊断”):
- LCP——优化最大的可见元素(首屏主图、标题区块、视频封面)
- INP——保持主线程空闲;拆分长任务,让每次交互(不只是首次交互)都能及时响应
- CLS——在动态内容加载前预留空间
- TTFB 和 FCP(< 1.8s)是上游关卡:它们限制着所有后续节点,因此应优先修复
- 在生产环境中使用真实用户监控(RUM)进行测量——实验室/合成测试无法覆盖真实设备和网络差异
代码应用:
| 场景 | 模式 | 示例 |
|---|---|---|
| LCP | 预加载 LCP 元素;提高其优先级 | <img src="hero.webp" fetchpriority="high"> |
| INP | 拆分长任务;让出主线程 | scheduler.yield() 或使用 setTimeout 分块 |
| CLS | 为异步内容预留空间 | <img width="800" height="600"> 或 CSS aspect-ratio |
| 性能预算 | 当指标回退并超出“快速诊断”阈值时,让 CI 失败 | 使用 Lighthouse CI 断言检查 LCP/INP/CLS |
当某项指标处于红色状态时,请参阅 references/core-web-vitals.md——其中包含各指标的调试工作流(LCP/INP/CLS 表现不佳时应检查什么)、实验室测试与 RUM 工具对照,以及各项指标的优化清单。
6. 实时通信
核心概念: 当数据必须持续流动时,传输方式的选择——WebSocket、SSE 或长轮询——决定了延迟、资源使用量和可扩展性。
为何有效: HTTP 的请求-响应模式会给每次实时更新增加开销。WebSocket 支持全双工,帧开销约为 2 字节;SSE 则通过普通 HTTP 实现更简单的服务端到客户端推送。应根据数据流的方向和频率选择传输方式,而不是默认采用功能最强的选项。
关键要点:
- WebSocket:双向通信(聊天、游戏、协作编辑);SSE:仅服务端到客户端,支持自动重连、对代理友好且更简单
- 长轮询仅用作后备方案——重复发送 HTTP 请求会带来很高的开销
- 每个 WebSocket 都是单独的 TCP 连接,不经过 HTTP/2 多路复用
- 发送心跳/ping 帧——移动网络会悄无声息地断开空闲连接
- 以指数退避方式重连,并在断开期间将消息加入队列
代码应用:
| 场景 | 模式 | 示例 |
|---|---|---|
| 聊天/协作 | WebSocket + 心跳 + 重连 | new WebSocket('wss://...'),每 30s 发送一次 ping |
| 实时动态/通知 | 使用 SSE 实现服务端到客户端的流式传输 | new EventSource('/api/updates') |
| 连接韧性 | 重连时采用指数退避 | 1s、2s、4s、8s……上限为 30s |
| 扩展 | 在 WebSocket 服务端后部署发布/订阅代理 | Redis Pub/Sub 或 NATS |
构建实时功能时,请参阅 references/real-time-communication.md——其中介绍了 WebSocket 连接/心跳/重连生命周期、SSE EventSource 模式,以及如何通过发布/订阅代理扩展扇出。
常见错误
| 错误 | 失败原因 | 修复方法 |
|---|---|---|
| 增加带宽以修复页面加载缓慢 | 瓶颈在于延迟,而非吞吐量 | 减少往返:预连接、缓存、使用 CDN |
| 一开始就加载所有 JS | 阻塞解析的脚本会延迟绘制和交互 | 拆分代码;使用 defer;延迟加载非关键模块 |
| 不使用资源提示 | 浏览器发现关键资源的时间太晚 | 对首屏关键资源使用 preconnect + preload |
到处缺少 Cache-Control/no-store | 每次访问都会重新下载所有内容 | 正确设置 max-age + 内容哈希 |
| 忽略 CLS | 布局偏移会损害信任度和排名 | 为图片、嵌入内容和广告指定明确尺寸 |
| 什么都用 WebSocket | SSE/轮询足以满足需求时却引入不必要的复杂性 | 根据数据流选择传输方式;服务端推送使用 SSE |
| 在 HTTP/2 上进行域名分片 | 破坏多路复用;增加 TCP 连接 | 整合源;让 HTTP/2 进行多路复用 |
| 不启用压缩 | 文本资源以完整大小传输 | 在服务端/CDN 上启用 Brotli(首选)或 Gzip |
快速诊断
| 问题 | 如果没有 | 操作 |
|---|---|---|
| TTFB 是否低于 800ms? | 服务端或网络太慢 | 使用 CDN、服务端缓存,并检查后端 |
| LCP 是否低于 2.5s? | 最大元素加载太晚 | 预加载 LCP 资源;设置 fetchpriority="high" |
| INP 是否低于 200ms? | 主线程被阻塞 | 拆分长任务;延迟执行非关键 JS |
| CLS 是否低于 0.1? | 元素在渲染后发生偏移 | 指定明确尺寸;预留空间 |
| 静态资源是否使用内容哈希并已缓存? | 回访用户会重新下载资源 | 使用哈希文件名 + Cache-Control: immutable |
| 是否启用了 HTTP/2 或 HTTP/3? | 无法进行多路复用或标头压缩 | 在服务端启用 HTTP/2;通过 CDN 启用 HTTP/3 |
| 是否尽量减少了阻塞渲染的资源? | CSS 和同步 JS 会延迟首次绘制 | 内联关键 CSS;为脚本添加 defer;移除未使用的 CSS |
| 是否启用了压缩(Brotli/Gzip)? | 文本以未压缩状态传输 | 在服务端/CDN 上启用 Brotli;使用 Gzip 作为后备 |
延伸阅读
内容基于 Ilya Grigorik 编写的浏览器网络与 Web 性能综合指南:
- 《High Performance Browser Networking》,作者 Ilya Grigorik(网络协议、浏览器内部机制和性能优化的完整参考资料)
- hpbn.co -- 作者维护的免费在线版
关于作者
Ilya Grigorik 是一名 Web 性能工程师,曾在 Google 工作十余年,参与 Chrome、Web 平台性能和 HTTP 标准的相关工作,并共同主持 W3C Web Performance 工作组。他的著作 High Performance Browser Networking(O'Reilly,2013)被广泛视为浏览器如何与网络交互的权威参考资料。