Web页面全链路性能优化指南
性能优化不单指优化一个页面的打开速度,在开发环境将一个项目的启动时间缩短使开发体验更好也属于性能优化,大文件上传时为其添加分片上传、断点续传也属于性能优化。在项目开发以及用户使用的过程中,能够让任何一个链路快一点,都可以被叫做性能优化。
本文会对web页面的全链路进行完整的讲解并针对每一步找到能做的性能优化点,本文的目标是极致的性能优化。
因为针对性能优化,能做的点会特别特别的多,覆盖着整个互联网的访问流程,因此此文章的内容会比较多且杂,笔者会尽量对内容进行分类讲解。
本文的大致流程为先讲理论知识,比如如何评价一个页面的性能好与不好、如果获取性能指标,如何使用各种性能相关工具,浏览器如何获取并渲染页面。笔者认为这些都是基础,只有了解了这些基础才能开始考虑如何去优化。
接下来我们会进入性能优化环节,在这个环节我会详细讲解在页面的整个流程中,哪些地方可以做哪些优化。
目录
进程与线程
输入url到页面展示完整过程
1.用户输入
2.卸载原页面并重定向到新页面
3.处理Service Worker
4.网络请求
5.服务端响应
6.浏览器渲染详细流程
浏览器处理每一帧的流程
Chrome Performance(性能)
Chrome Performance 工具的使用
Performance API介绍
使用Performance API获取性能相关指标
Coverage(覆盖率)
Lighthouse
Network(网络)
网络请求中的Timing(时间)
网络请求的优先级
网页总资源信息
Network配置
网络优化策略
减少HTTP请求数
使用HTTP缓存
使用 HTTP/2.0
避免重定向
使用 dns-prefetch
使用域名分片
CDN
压缩
使用contenthash
合理使用preload、prefetch
浏览器渲染优化策略
关键渲染路径
强制同步布局问题
如何减少重排与重绘
静态文件优化策略
图片格式
图片优化
HTML优化
CSS优化
JS优化
字体优化
浏览器储存优化策略
Cookie
LocalStorage
SessionStorage
IndexDB
其他优化策略
使用PWA提高用户体验
浏览器渲染原理
我们需要知道浏览器是如何渲染一个页面的,我们才能知道如何对页面进行性能优化,所以这里我们对一些基础知识进行讲解
进程与线程
浏览器有多种进程,其中最主要的5种进程如下
浏览器进程 负责界面展示、用户交互、子进程管理、提供存储等 渲染进程 每个页面都有一个单独的渲染进程,用于渲染页面,包含webworker线程 网络进程 主要处理网络资源加载(HTML、CSS、JS、IMAGE、AJAX等) GPU进程 3D绘制,提高性能 插件进程 chrome插件,每个插件占用一个进程
输入url到页面展示完整过程
图1
1.用户输入
用户在浏览器进程
输入并按下回车健后,浏览器判断用户输入的url是否为正确的url,如果不是,则使用默认的搜索引擎将该关键字拼接成url。
2.卸载原页面并重定向到新页面
然后浏览器会将现有页面卸载掉并重定向到用户新输入的url页面,也就是图中【Process Unload Event】和【Redirect】流程。
此时浏览器会准备一个渲染进程
用于渲染即将到来的页面,和一个网络进程
用于发送网络请求。
3.处理Service Worker
如果当前页面注册了Service Worker那么它可以拦截当前网站所有的请求,进行判断是否需要向远程发送网络请求。也就是图中【Service Worker Init】与【Service Worker Fecth Event 】步骤
如果不需要发送网络请求,则取本地文件。如果需要则进行下一步。
4.网络请求
OSI网络七层模型:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
在实际应用中物理层、数据链路层被统称为物理层,会话层、表示层、应用层被统称为应用层,所以实际使用时通常分为4个层级
【物理层】>【网络层(IP)】>【传输层(TCP/UDP)】>【应用层(HTTP)】
也就是图中【HTTP Cache】、【DNS】、【TCP】、【Request】、【Response】步骤
图2
浏览器会拿着url通过网络进程
进行如下步骤
根据url查询本地是否已经有强制缓存,如果有则判断缓存是否过期,如果没过期则直接返回缓存内容,也就是图1中【HTTP Cache】步骤
如果没有强制缓存或者缓存已过期,则将该请求加入队列进行排队准备发送网络请求,也就是图2中【正在排队】,然后进入DNS解析阶段,也就是图1中【DNS】以及图2中的【DNS查找】,DNS根据域名解析出对应的IP地址。(DNS基于UDP)。
然后使用IP寻址找到对方,然后根据IP地址+端口号创建一个TCP连接(三次握手),也就是图1中【TCP】以及图2中的【初始连接】创建完成后利用TCP连接来传输数据。(TCP会将数据拆分为多个数据包,进行有序传输,如果丢包会重发,TCP的特点是可靠、有序)
判断当前协议是否为https,如果为https,则进行SSL协商,将数据进行加密,如果为http协议则不进行加密(明文传输),也就是图2中的【SSL】。
开始发送http请求(请求行/请求头/请求体),也就是图1中【Request】以及图2中的【已发送请求】。HTTP协议有多个版本,目前使用最多的版本为HTTP/1.1,HTTP/1.1发送完成后默认不会断开。keep-alive 默认打开,为了下次传输数据时复用上次创建的连接。每个域名最多同时建立6个TCP连接,所以同一时间最多发生6个请求。
HTTP协议的各个版本特性如下:
HTTP/0.9
没有请求头和响应头,不区分传输的内容类型,因为当时只传输HTML。HTTP/1.0
提供了请求头和响应头,可以传输不同类型的内容数据。根据请求响应头的不同来处理不同的资源,HTTP1.0每次发完请求都会断开TCP连接。有新的请求时再次创建TCP连接。HTTP/1.1
默认开启了 keep-alive ,它能够让一个TCP连接中传输多个HTTP请求,也叫链路复用
。但一个TCP连接同一时间只能发送一个HTTP请求,为了不阻塞多个请求,Chrome允许创建6个TCP连接,所以在HTTP/1.1中,最多能够同时发送6个网络请求。HTTP/2.0
HTTP/2.0使用同一个TCP连接来发送数据,他把多个请求通过二进制分贞层实现了分贞,然后把数据传输给服务器。也叫多路复用
,多个请求复用同一个TCP连接。HTTP/2.0会将所有以:
开头的请求头做一个映射表,然后使用hpack
进行压缩,使用这种方式会使请求头更小。服务器可主动推送数据给客户端。HTTP/3.0
使用UDP实现,在UDP上一层加入一层QUIC
协议,解决了TCP协议中的队头阻塞问题。服务器收到数据后解析HTTP请求(请求行/请求头/请求体),处理完成后生成状态码和HTTP响应(响应行/响应头/响应体)后返回给客户端,也就是图2的【等待中】在做的事情。
客户端接收到HTTP响应后根据状态码进行对应的处理,如果状态码为304则直接代表协商缓存生效,直接取本地的缓存文件。如果不是则下载内容。也就是图1中【Response】以及图2中的【下载内容】步骤。
5.服务端响应
在4.网络请求
第6
步中,服务器收到HTTP请求后需要根据请求信息来进行解析,并返回给客户端想要的数据,这也就服务端响应。
服务端可以响应并返回给客户端很多种类型的资源,这里主要介绍html
类型
目前前端处理服务端响应html请求主要分为SSR服务端渲染与CSR客户端渲染,CSR就是返回一个空的HTML模版,然后浏览器加载js后通过js动态渲染页面。SSR是服务端在接受到请求时事先在服务端渲染好html返回给客户端后,客户端再进行客户端激活。
在打开一个站点的首屏页的完整链路中,使用SSR服务端渲染时的速度要远大于CSR客户端渲染,并且SSR对SEO友好。所以对于首屏加载速度比较敏感或者需要优化SEO的站点来说,使用SSR是更好的选择。
6.浏览器渲染详细流程
浏览器渲染详细流程主要在4.网络请求
中的地7
步。浏览器下载完html
内容后进行解析何渲染页面的流程。
渲染流程分为4种情况,
HTML中无任何CSS相关标签 CSS相关标签在HTML最顶部,且在解析到内容标签( )时已经解析完CSS相关标签
CSS相关标签在HTML最顶部,但在解析到内容标签( )时CSS相关标签尚未解析完
CSS相关标签在HTML最底部
下面的流程是对上图的文字版解析。读者可将以上4种情况分别带入到如下的渲染流程中走一遍。就能理解浏览器的完整渲染过程了。
【HTML】
浏览器收到html资源后先预扫描和