前端性能优化
前端性能优化
月晕性能优化
性能优化是老生常谈的问题,比如页面首屏渲染时间,丝滑程度等在现在的 web 应用中都显示十分重要,决定你的产品能否有更好的体验
度量
核心的 web 指标
Largest Contentful Paint(LCP): 最大内容绘制,测量加载性能,为了有良好的体验,LCP 在页面首次开始加载后的 2.5s 内出现
First Input Delay(FID): 首次输入延迟,测量交互性,100ms 内
Cumulative Layout Shift(CLS): 积累布局偏移,测量视觉稳定性,0.1s 内
FCP(First Contentful Paint): 首次内容绘制
TBT(总阻塞时间)、TTI(可交互时间) 等等等
可以通过浏览器的 performance API 获取,也可以调用一些包去获取上传
页面流畅度
页面流畅度一般使用流畅度(FPS)衡量,一般 50-60 会很流畅
Lighthouse & Chrome Devtools
Lighthouse 是谷歌开源的一款 Web 前端性能测试工具,它将针对此页面运行一连串的测试,然后生成一个有关页面性能的报告,可以直接在 chrome 中使用。Lighthouse Performance 项的总和得分由 5 个指标的性能按一定比例综合计算得到
Chrome Devtools Performance 也是可以分析运行时性能的良好工具
提升服务器的响应时间
页面中早建立连接
对服务器请求也会影响 LCP,尤其是当浏览器需要这些请求来在页面上显示关键内容的情况下。使用 rel=”preconnect”来告知浏览器您的页面打算尽快建立连接
1 | <head> |
开启 HTTP/2 or HTTP/3
- HTTP1.1 中 Chrome 中有个机制是默认运行同时建立 6 个 TCP 持久连接,使用持久连接时,虽然能公用一个 TCP 管道,但是在一个管道中同一时刻只能处理一个请求
- HTTP/2 支持多路复用、头部压缩、服务端推送等特性为网站性能带来较大的提升且可以减少优化工作,然而 HTTP/2 同样使用的 TCP 连接,那么无法避免的有 TCP 的队头阻塞
- HTTP/3 基于 UDP 的 QUIC 协议实现
缓存资源
浏览器缓存策略通过资源的 Response Header 来定义,如 cache-control、expires、Etag、last-modified
等 详细见浏览器的强制缓存和协商缓存
CDN
CDN(Content Delivery Network 内容分发网络):指一种通过互联网连接的电脑网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户
典型的 CDN 包括下面三个部分组成
- 分发服务器系统: 最基本的工作单元就是 Cache 设备,cache(边缘 cache)负责直接响应最终用户的访问请求,把缓存在本地的内容快速地提供给用户
- 负载均衡系统: 主要功能是负责对所有发起服务请求的用户进行访问调度,确定提供给用户的最终实际访问地址。两级调度体系分为全局负载均衡(GSLB)和本地负载均衡(SLB)。
- 运营管理系统: 运营管理系统分为运营管理和网络管理子系统,负责处理业务层面的与外界系统交互所必须的收集、整理、交付工作,包含客户管理、产品管理、计费管理、统计分析等功能。
CDN 作用
CDN 一般会用来托管 Web 资源(包括文本、图片和脚本等),可供下载的资源(媒体文件、软件、文档等),应用程序(门户网站等)。使用 CDN 来加速这些资源的访问。
- 用户收到的内容来自最近的数据中心,延迟更低,内容加载更快
- 部分资源请求分配给了 CDN,减少了服务器的负载
CDN 原理
用户未使用 CDN 缓存资源的过程
- 浏览器通过 DNS 对域名进行解析,依次得到此域名对应的 IP 地址
- 浏览器根据得到的 IP 地址,向域名的服务主机发送数据请求
- 服务器向浏览器返回响应数据
用户使用 CDN 缓存资源的过程
- 对于点击的数据的 URL,经过本地 DNS 系统的解析,发现该 URL 对应的是一个 CDN 专用的 DNS 服务器,DNS 系统就会将域名解析权交给 CNAME 指向的 CDN 专用的 DNS 服务器
- CDN 专用 DNS 服务器将 CDN 的全局负载均衡设备 IP 地址返回给用户
- 用户向 CDN 的全局负载均衡设备发起数据请求
- CDN 的全局负载均衡设备根据用户的 IP 地址,以及用户请求的内容 URL,选择一台用户所属区域的区域负载均衡设备,告诉用户向这台设备发起请求
- 区域负载均衡设备选择一台合适的缓存服务器来提供服务,将该缓存服务器的 IP 地址返回给全局负载均衡设备
- 全局负载均衡设备把服务器的 IP 地址返回给用户
- 用户向该缓存服务器发起请求,缓存服务器响应用户的请求,将用户所需内容发送至用户终端
CDN 使用场景
- 使用第三方的 CDN 服务: 比如 jquery 等的
- 使用 CDN 进行静态资源的缓存: 将自己网站的静态资源放在 CDN 上,比如 js、css、图片等。可以将整个项目放在 CDN 上,完成一键部署。
- 直播传送
服务端渲染
优化手段只能在一定的限度内让我们的速度更快,但是如果想直出等效果需要改用不同的渲染方式去达到
传统的 SSR
传统的 SSR 也称为后端模板渲染,常见的就是 jsp 和 php,服务器在收到浏览器的页面请求后,使用模板引擎将页面模板与数据拼接成 HTML 返回
流程如下
- 浏览器输入 URL 地址–>浏览器向服务端请求页面
- 服务端收到请求–>路由匹配找到对应组件–>获取数据填充模板–>返回拼接数据引入 html
- 浏览器获取数据后开始渲染页面–>有 script 标签后再次向服务器请求 js –> 服务端收到请求返回 JS –> 浏览器收到 JS 后开始给各个页面注入交互
特点:
- 首屏渲染快,客户端拿到的 HTML 是直接带数据的,首屏渲染直接有内容
- 利于 SEO,服务端返回的 HTML 是带数据的
- 避免首屏请求过多问题,也将传统的 3 次串性 http 请求合并为 1 次(请求 HTML、请求 JS、请求首屏数据)
- 页面数据每次变动时,都需要重新请求完整的页面,性能差、服务端压力大、代码混乱、无法管理
CSR 渲染
服务端收到客户端请求后,只会返回前端打包生成的无页面内容的 HTML。需要客户端另外自行加载执行 JS,完成页面渲染。若需要页面首屏数据时,再去请求服务端,获取最新数据,更新视图
特点:
- 前后端分离解耦
- 可以进行页面局部刷新,无需请求完整页面,用户体验好
- 节省服务端性能,不用支持渲染
- 首屏渲染慢、不利于 SEO、首屏请求多
同构 SSR
采用一套代码、构建双端逻辑、最大限度的重用代码
既能在服务端渲染完成页面结构,又能在客户端渲染,绑定各客户端交互事件
同构 SSR 的出现主要基于
- Nodejs 存在,提供了一套服务端的 JavaScript 的运行时
- 虚拟 DOM 存在,引入虚拟 DOM 为 Nodejs 操作虚拟 DOM 提供了可能
React 中的同构主要包括了
- 路由同构
- 渲染同构
- 数据同构获取
SSG、ISR、ESR
SSG(Static Site Generation):静态站点生成即静态渲染
无需使用 Web 服务器实时动态编译 HTML,而是在构建时(build time)为每个 URL 生成静态 HTML 文件,可以使用 CDN 加快页面访问
ISR(Incremental Site Rendering: 增量式渲染 = SSG + CSR)
ESR(Edge Side Rendering 边缘渲染)
ESR 渲染利用了 CDN 能力,CDN 节点相比于 Server,距离用户更近,有着更短的网络延时。ESR 会在 CDN 上缓存页面的静态部分,这样在用户访问页面时,可以快速返回给用户静态内容,同时在 CDN 节点上也发起动态部分内容请求,在动态内容获取之后,利用流的方式,继续返回给用户
阻塞渲染的 JS 和 CSS 资源
以 Webpack 打包工具举例去优化打包中的策略
削减 JS 和 CSS 的体积
引入 webpack-bundle-analyzer 插件对现有的分包进行分析,做产物分析,比如会遇到
- 剔除重复的第三方库
- 第三方库的筛选
- 按需引入
- 调试工具或者非线上依赖不打入包中
合理拆包、延迟、懒加载未使用的资源
使用内置的 splitChunks 配置去对 js 文件进行拆包,比如第三方库的拆分,方便浏览器缓存或者放入 CDN 中,引入 CDN 去实现
分包与业务相关,可以去动态加载一个 js 文件,比如动态路由之类的,等待使用了才回去加载 js 文件,让首页更加纯净,我们也会先加载用户最想看见的包,在会去加载一些没那么重要的包
- 压缩代码:删除多余的代码、注释、简化代码的写法等等⽅式。
- 利用 CDN 加速:在构建过程中,将引⽤的静态资源路径修改为 CDN 上对应的路径。可以利⽤ webpack 对于 output 参数和各 loader 的 publicPath 参数来修改资源路径
- Tree Sharking:将代码中永远不会⾛到的⽚段删除掉。可以通过在启动 webpack 时追加参数 –optimize-minimize 来实现
- Code Splitting:将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利⽤浏览器缓存
- 提取第三方库:SplitChunksPlugin 插件来进⾏公共模块抽取,利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码
关键的 CSS
CSS 文件是渲染阻塞资源,这也就意味着,假如有个比较大的 css 文件,这个过程耗时就比较长。而我们初始页面实际上需要的 css 样式有多少
考虑将首屏内容 CSS 作为关键 CSS 提取出来,或者内联到 HTML 文档的 <head>
中(适合关键 CSS 体积较小的场景),从而无需发出额外的请求就能获取这些样式,或者作为最高优先级阻塞加载,剩余的 CSS 可以延迟加载或者根据分包懒加载。
加速缓慢资源加载
优化和压缩图片资源
通过图片压缩、格式自定义、分辨率自定义等方式去减小图片体积
预加载重要的资源
当有重要的资源比如字体、背景等加载的较晚时,采用<link rel="preload">
的方式实现预加载,以便需要时可以直接使用