猜你喜欢
前端性能揭秘

前端性能揭秘

书籍作者:佘锦鑫 ISBN:9787121442407
书籍语言:简体中文 连载状态:全集
电子书格式:pdf,txt,epub,mobi,azw3 下载次数:8368
创建日期:2023-04-27 发布日期:2023-04-27
运行环境:PC/Windows/Linux/Mac/IOS/iPhone/iPad/Kindle/Android/安卓/平板
内容简介

本书主要介绍用于指导前端性能优化工作的通用优化方法,从网络、浏览器、构建工具、跨端技术和CDN 等方面介绍不同技术、系统对性能的影响,同时帮助读者了解如何有效优化性能。本书从性能的度量、分析和实验这三个方面开始介绍。首先介绍性能优化的一些通用方法,然后将性能作为一个切面帮助读者了解与前端技术栈和性能有关的知识。从这个切面观察,这些系统的工作原理等知识被赋予了另外一层意义,通过这种联系把工作原理真正运用到工作中,在性能优化方面发挥重要作用。本书面向的读者为具有一定经验的 Web 开发工程师,以及对前端开发或 Web 开发有一定了解的开发人员。同时,假定读者能够进行简单的网页开发,并且具备相关的基础知识。


作者简介

佘锦鑫,花名当轩。毕业于江南大学理学院,阿里巴巴前前端技术专家,曾负责阿里海外版性能优化,讲师、开源爱好者。现就职于网易云音乐,对Web性能、跨端、可视化搭建等领域有较深入的理解。


编辑推荐

1.前端老鸟也不甚了了的前端性能优化硬核知识。

2.性能是前端技术挑战巅峰与工程师追求的极限。

3.涉及底层网络到上层框架值得长期投入众课题。

4.三位一体思路:性能度量+工具分析+优化解决。

5.从用户体验角度理解浏览器处理页面生命流程。

6.剖析数据收集分析、各项性能指标定义及优化。


前言

推荐序

对于工程师来说,性能永远是绕不开的话题。目前硬件和网络都在飞速发展,然而新的软件和交互形式在发挥想象力的同时也在最大化地发挥硬件和网络的潜力,从长远来看性能仍然是工程师关心的话题。

对于用户来说,性能同样是用户体验的核心与基础,大部分用户可能并不理解性能这个概念,但他们永远想要启动更快、响应更迅速的软件。

相比其他工程师,前端工程师是直接和用户打交道的一群人,直接对用户机器上运行的软件体验负责。当讨论后端性能时,在大部分情况下讨论的是吞吐量、并发数和响应时间等,关心的是软件运行在服务器上的性能表现。当讨论前端性能时,在更多情况下讨论的是用户感受到的白屏时间、延迟和卡顿等。这种差异使前端性能和用户体验的关联更加密切,也赋予了前端工程师独特的使命。

想要解决性能问题,开发人员需要分析现状、提出设想、进行验证,而这些都需要开发人员对相关系统的知识有足够的了解。本书从两个方面介绍了性能领域,前面介绍了“度量、分析、实验”的方法论,后面则以性能为切面介绍了前端生态与性能有关的方方面面。

读者在阅读本书时可以按照自己的需要决定阅读顺序,但至少先完整地阅读方法论部分。相比具体的知识点,方法论能为真正的性能优化工作提供通用化的思路,性能优化作为一个系统化的工程需要行之有效的思路,而不仅仅是照搬点状的知识点。

而以性能为切面也可以为读者看待前端生态提供一个不一样的视角,很多基础知识看起来和日常工作似乎没有太多的联系,但从性能的视角可以看到这些协议、工具、方案背后的思考和对实际应用的切实影响。性能并非孤立的技术领域,而是和系统中的每个环节都息息相关,为读者更深入地理解系统提供了视角。

写前端性能优化对作者有很高的要求,要有深度实践的经验并形成一定的方法论。当轩是资深开源开发人员,曾在第十五届D2前端技术论坛担任讲师。希望本书能够给广大读者带来醍醐灌顶式的帮助。

——Node.js布道者,《狼书》作者,桑世龙(花名狼叔)




前言

性能对于开发人员来说是一个经久不衰的话题,也是用户体验的重要因素。当打开一个页面或 App 时,无论你是在寻找商品、阅读高质量的新闻,还是在看有趣的短视频,都不愿意等待。

很多人可能有耐心花费一两个小时在一家火锅店门口排队,但几乎没有人愿意等 30s 去加载一个短视频。事实上,对于大多数的 App 或网站来说,别说是 30s,即使是 3s 也足以让大量用户放弃等待转而去做其他的事情。

Google 发现,如果页面加载时间超过 3s,53%的移动网站访问活动将难以为继。

有人可能会问,如今计算机和手机的性能都在飞速发展,性能优化还重要吗?5G 时代已经来临,无处不在的高速网络是否已经让我们不需要再那么在意性能问题?

其实,在 Web 领域,安迪-比尔定律仍然成立。

安迪-比尔定律源于“Andy gives, Bill takes away.”。Andy 指的是 Intel 原 CEO 安迪·格鲁夫,Bill 则是 Microsoft 原 CEO 比尔·盖茨。这句话的意思是,Intel 一旦向市场推广了一种新型芯片,Microsoft 就会及时升级自己的软件产品,以匹配新型芯片的高性能。硬件提高的性能,很快就被软件消耗掉了。

对于 Web 领域来说,网络和终端设备的性能确实在飞速发展。然而,几十年来 Web 技术也变得越来越复杂,在网络上传输的不再是一个简单的页面。Web 技术本身也在不停地更新换代,传输页面的体积、执行脚本的复杂度等都在不断增加。

让我们回到万维网(World Wide Web)诞生的 20 世纪 90 年代,第一个网页浏览器WorldWideWeb 仅支持 HTML 格式的图片、文字和超链接。

经过几十年的发展,在网络上传输的内容越来越丰富,使用浏览器打开的不再是一个仅包含图片、文字和超链接的页面,而是高清流媒体、实时网络直播,甚至是直接在浏览器中运行的专业协同应用。

可以预见的是,这种复杂度会日益增加,越来越多原来只能在桌面平台上运行的大型软件也出现在了 Web 平台上,以借助 Web 平台易于传播、跨平台等特性,充分发挥协作互通的优势。例如,如图 0-2 所示的设计协同工具 Figma,就可以完全运行在浏览器中,而以往这种专业的设计工具只能作为桌面软件使用。

从 2011 年到 2020 年,桌面端和移动端的页面传输字节数(加载完成一个页面需要传输的数据量)逐年上涨,分别约增加了 329%和 1178%。

同时,随着网络基础建设的不断更新换代,更多原来受限于基础设施无法广泛满足的需求大量涌现。例如,近几年短视频的兴起,很大程度上就是因为大多数用户的网络能够在可以接受的时间内加载完视频。用户随时看新鲜且有趣视频的需求一直存在,只是之前的硬件条件难以满足用户的需求。

这就是安迪-比尔定律在 Web 领域没有失效的原因。可以想象,随着未来网络状况的进一步改善,又会有新的媒体和应用形式消耗提升的网络传输能力。它既可能是基于 AR、VR 的视频会议、协作办公,也可能是更加复杂、支持更多人参与协作的办公协同工具。尽管提供硬件和软件的可能不再是 Intel 和 Microsoft,但只要人们对于新功能和体验的追求一直存在,性能优化就是经久不衰的话题。

1.性能优化的魅力

上面从现实的角度出发解释了性能优化的重要性,可见重视性能优化是有客观基础的。

其实,性能优化本身就具备无可比拟的魅力。

很多人都听过斯坦门茨画一条线 1 万美元的故事,有些人说这个故事反映了知识就是财富,有些人说这个故事反映了细节决定成败。故事的真实性已经无法考证,但是笔者非常喜欢这个故事。

故事是下面这样的。美国福特公司曾经有一台电机出现故障,导致整个车间都不能运转。福特公司请来很多专家检查,就是找不到问题在哪里。于是请来斯坦门茨,斯坦门茨在电机旁聚精会神地听了 3 天,又要了梯子,爬上爬下忙了很久。最后他在电机的一个部位用粉笔画了一条线,写下了“这里的线圈多绕了 16 圈”。福特公司按图索骥解决了故障。

在平均月薪为 5 美元的当时,斯坦门茨索要了 1 万美元的酬劳:画一条线,1 美元;知道在哪儿画线,9999 美元。

如果说工程师最大的快乐来自创造,那么笔者认为第二大的快乐来自对精密系统的理解。从中不仅可以领略前人解决问题的设计方案所蕴含的智慧,还能享受抽丝剥茧最终精准找到问题的成就感。

性能优化就是一个典型场景,我们要做的是理解复杂系统并从中找到性能问题的关键所在。有时我们甚至能根据问题的表现和对系统的理解,在没有直接发现具体问题时就推测出出现问题的真正原因。例如,海王星先通过数学推算被发现再被人们实际观测到的过程就充满了预言的魔力。

海王星的发现史如下。

?? 1821 年天王星(不是海王星)的轨道表发布,但是观测表明轨道存在偏差,于是有人猜测其受到附近一个巨大天体的扰动。

?? 1846 年,通过数学方法推导出了海王星的轨道,之后开始搜寻,并于当年 9 月 23 日发现海王星。

2.性能优化 = 分析方法 + 技术原理

自工作以来,笔者有幸接触过不同场景的性能优化,包括面向计算机的和面向手机的、纯 Web 技术的和 Weex/React Native 等技术的,以及国内的和海外的。

每次接触到一个新场景,笔者都发现上一个场景的经验很难直接发挥作用,了解性能优化的读者大多听说过“雅虎三十五条优化军规”,里面总结了性能优化需要遵循的一些规则,如合并请求等。在大多数情况下,直接套用这些规则并不会为页面带来非常明显的性能收益。

但是,其背后的分析思路总是相似的,能够用来找到一套行之有效的方法帮助我们一步步接近性能目标。相比于记住正确但未必有效的具体规则,掌握这些通用的方法能让我们在复杂的生产环境中找到正确的道路。

因此,本书把“度量”、“分析”和“实验”部分放在开头部分,把方法放在具体的技术细节之前,用案例和思考相结合的方式建立面对性能问题时的解决思路,有了方法的指导,我们在遇到具体问题的时候才能进行具体分析。

如果说分析方法是解决性能问题的指南针,那么对技术原理和系统的理解就是照明灯,只有方向但看不到脚下的路是无法前行的。优化一个系统的性能也一样,即使分析出这个系统在某个阶段的性能存在问题,如果不理解系统背后的运行原理,就好像知道方向却看不见路,只能摸黑前进。

笔者在优化过程中常常根据一些有趣的知识来梳理思路,所以在介绍如何做性能优化的同时,也以性能为引子来介绍网络、浏览器、前端技术栈等的技术原理。其中的很多原理读者可能从其他地方了解过,但是带着对性能的疑问阅读本书,可以帮助读者了解更多前人为了更好的体验和性能在这些复杂系统中付出的心血。

3.关于本书

比较幸运的是,自工作以来笔者在不同的场景一直面临各种性能挑战。刚开始只是打地鼠式地逐个解决问题,在凭着猜测和主观感受进行简单的优化后就认为已经解决了性能问题。随着面临的挑战越来越多,笔者不得不思考如何科学地衡量当前的性能状况、如何科学地分析性能存在的问题和优化方向,以及如何科学地验证优化的效果。

在优化过程中,性能作为一个引子贯穿整个与 Web 开发相关的各种系统及这些系统的原理,笔者认为这些平时看起来并没有直接作用的理论知识其实可以切实帮助我们改善用户体验,并且改善的效果直接反映为数字指标。

笔者撰写本书一方面是对过去几年的工作进行总结,另一方面也希望能给想要提高用户端性能、改善用户体验但是不知道应该从哪里开始的读者一些启发。对于想在 Web 技术上更进一步的读者来说,性能也是一个非常有趣的话题和线索。

性能是一个涉及甚广且技术细节较多的话题,笔者在写作过程中尽可能搜集相关标准、资料来验证书中的细节。由于笔者的经验和视野有限,加上部分技术细节存在时效性问题,因此书中难免存在局限和疏漏,如有可改进之处欢迎各位读者批评斧正。


目录

第 1 篇 从 Vite 起步

第 1 章 从实践开始2

1.1 Hello World2

现在开始2

使用 DevTools4

第一个优化6

1.2 现实开发的例子7

设置开发环境7

Vite8

vite build9

进一步优化11

引入 antd11

按需引入13

动态 import14

1.3 小结15

第 2 篇 性能优化方法论

第 2 章 度量18

2.1 科学的方法19

从一个客户反馈说起19

不度量性能,就无法优化

性能19

真实的用户端性能20

2.2 初识 Performance API21

performance.now()方法21

构建首屏指标23

2.3 均值、分位数和秒开率23

均值24

分位数25

秒开率26

如何选择合适的统计指标26

2.4 度量首屏27

FP27

FCP27

FMP28

如何度量 FMP28

选定并度量首屏30

2.5 度量流畅度30

度量流畅度的指标31

可视化工具31

用户端度量32

2.6 Core Web Vitals34

LCP34

FID38

CLS39

2.6 小结41

第 3 章 分析42

3.1 分析方法43

确定目标43

收集数据43

清洗数据44

统计值分析44

时序分析45

维度分析46

相关性分析48

3.2 常用的过程指标48

TTFB49

DOMReady 和 Load50

3.3 Performance API 详解51

Navigation Timing API51

Peformance Entry API53

Resource Timing54

Navigation Timing Level 255

Paint Timing56

User Timing56

3.4 分阶段性能分析58

常用的指标58

其他值得分析的指标59

3.5 小结59

第 4 章 实验60

4.1 优化不是照搬军规61

时代在发展61

优化的木桶效应明显62

用户环境差异大62

性能实验62

4.2 用实验验证优化63

混沌问题64

设计实验64

分桶65

上报和分析数据68

A/B Test 背后的数学68

结论不重要,重要的是方法69

4.3 用实验改进优化69

建立模型69

实验修正70

4.4 小结71

第 5 章 工具72

5.1 DevTools73

Network 面板73

Performance 面板76

5.2 WebPageTest81

发起测试82

报告83

Waterfall 视图83

5.3 小结87

第 3 篇 网络协议与性能

第 6 章 TTFB 为什么这么长90

6.1 TTFB 的合理值91

精确定义92

RTT92

RTT 一般需要多久93

TTFB 的构成 93

实验环境验证94

6.2 如何优化 TTFB95

减少请求的传输量96

减少服务器端的处理时间96

减少 RTT98

TTFB 的值越小越好吗98

6.3 小结99

第 7 章 建立连接为什么这么慢100

7.1 建立连接应该耗时多久101

TCP 协议101

建立连接需要多少个 RTT101

抓包验证102

7.2 如何优化建立连接的耗时103

减少物理距离103

preconnect103

复用连接103

域名收拢104

TCP Fast Open104

QUIC 和 HTTP/3104

7.3 小结105

第 8 章 Fetch 之前浏览器在干什么106

8.1 重定向107

HTML 重定向109

有哪些重定向109

8.2 浏览器打开耗时112

初始化标签页的时间112

unload 的耗时112

8.3 如何优化 beforeFetch 耗时114

重定向逻辑前置115

合并重定向115

避免使用短链116

使用 beforeFetch 度量和

分析116

8.4 小结117

第 9 章 HTTPS 协议比 HTTP 协议

更慢吗118

9.1 HTTPS 协议为什么安全119

对称加密和非对称加密119

SSL/TLS 的实现120

SSL/TLS 握手122

TLS False Start124

TLS 1.3124

9.2 HTTPS 协议如何吊销证书125

CRL125

OCSP126

OCSP Stapling126

浏览器支持的情况126

证书类型127

证书验证机制对性能的影响129

9.3 HTTPS 协议更慢吗129

确保证书链完整129

启用 TLS 1.3129

不滥用 EV 证书130

开启 OSCP Stapling130

9.4 小结130

第 10 章 HTTP/2、HTTP/3 和性能131

10.1 HTTP/2 和性能131

连接复用为什么不生效131

头部压缩对我们有什么影响137

为什么没有广泛使用 Server

Push140

10.2 为什么还需要 HTTP/3144

HTTP/2 存在什么问题145

HTTP/3 如何解决问题146

10.3 小结148

第 11 章 压缩和缓存150

11.1 传输速度和压缩速度如何兼得151

Content-Encoding151

gzip 压缩和 br 压缩152

实时压缩152

离线压缩153

如何优化传输性能154

11.2 HTTP 缓存什么时候会失效154

缓存不仅仅是浏览器的

事情154

缓存 Header154

11.3 小结157

第 4 篇 浏览器与性能

第 12 章 浏览器和性能160

12.1 第一次渲染时都发生了什么161

最小的渲染路径162

尽快返回 HTML167

减少资源的阻塞167

12.2 为什么 DOM 操作很慢168

帧168

重排169

重绘170

访问 DOM 属性170

如何优化 DOM 操作171

12.3 小结172

第 13 章 异步任务和性能173

13.1 事件循环机制174

为什么要有事件循环174

多线程阻塞模型174

事件循环175

13.2 宏任务和微任务176

13.3 Promise 的 polyfill 性能178

如何正确实现 Promise178

13.4 requestAnimationFrame180

13.5 小结181

第 14 章 内存为什么会影响性能182

14.1 内存182

内存管理183

14.2 内存泄漏188

内存泄漏和性能188

常见的导致内存泄漏的原因188

内存泄漏问题的诊断工具189

14.3 小结191

第 15 章 使用 ServiceWorker 改善

性能193

15.1 ServiceWorker 概述194

AppCache 194

ServiceWorker 195

ServiceWorker 能做什么195

15.2 使用 ServiceWorker 进行缓存196

Cache API196

IndexDB201

控制缓存的 Cache Key201

更加灵活的缓存更新策略203

15.3 API 提前加载204

15.4 ServiceWorker 冷启动205

开启 Navigation Preload206

消费 Navigation Preload206

15.5 小结207

第 16 章 字体对性能的影响208

16.1 字体导致的布局偏移208

如何定位布局偏移208

16.2 如何避免字体带来的布局偏移210

如何尽快加载字体211

字体文件的格式211

字体的加载212

预加载字体213

裁剪字体的大小214

16.3 小结214

第 5 篇 前端工程与性能

第 17 章 构建工具和性能218

17.1 为什么需要打包219

CommonJS220

AMD220

CMD221

异步模块加载器222

依赖加载优化223

模块打包器224

ES Module225

17.2 构建工具可以做什么226

构建工具和构建优化227

为什么要优化打包体积227

Bundle 分析228

Tree Shaking229

Scope Hoisting231

Code Splitting233

代码压缩234

Vite 和 Bundleless237

17.3 小结237

第 18 章 服务器端渲染和性能239

18.1 SSR 和同构241

18.2 SSR 的性能优化241

缓存242

数据预取245

按需渲染245

流式渲染246

18.3 小结246

第 6 篇 跨端技术与 CDN

第 19 章 WebView 和性能248

19.1 WebView 和 Native 的区别249

LayoutInflater249

加载 XML 的具体过程250

Measure250

Layout251

Paint252

Surface253

SurfaceFlinger253

差异253

19.2 WebView 的通信成本254

JavaScript 调用 Native254

Native 调用 JavaScript258

双向通信258

通信对性能的影响259

减少通信数据量259

避免频繁通信259

19.3 React Native 的懒加载有何

不同260

Web 实现260

基于滚动容器的懒加载260

基于位置获取的懒加载262

虚拟列表263

19.4 React Native 如何减小打包

体积265

Metro265

度量266

分析266

手动 Tree Shaking267

利用 Babel 插件进行优化269

体积和性能的关系271

19.5 API 并行请求271

发起请求272

请求拦截273

一致性检验274

命中率分析274

19.6 小结274

第 20 章 CDN 和性能275

20.1 什么是 CDN275

解析276

边缘节点276

回源277

缓存策略277

20.2 如何提升缓存命中率278

如何在端侧统计缓存命中的

情况278

减少缓存分裂279

缓存忽略动态参数279

归一化 Vary Header280

长效缓存280

20.3 动态加速281

海外加速282

连接复用282

客户端连接复用282

HTTPS 优化283

动静分离283

压缩284

什么场景适合使用动态加速284

20.4 自动 polyfill284

什么是 polyfill284

Polyfill.io285

实现原理287

20.5 边缘计算和性能288

CDN 的可编程功能288

Hello World289

自定义 Cache Key289

前置重定向290

流式渲染290

20.6 小结291