1 查看首屏加载时间
performance.timing
是浏览器提供的一个对象,它包含了网页加载过程中各个关键阶段的 时间戳 数据,这些数据对于分析网页性能、识别加载瓶颈非常有用。
首屏加载时间,指的是 浏览器从相应用户输入网址,到首屏内容渲染完成的时间 ;
此时整个网页不一定全部渲染完成,但需要展示当前视窗需要的内容;
首屏加载是用户体验的重要环节。
控制台输入
(performance.timing.domComplete - performance.timing.navigationStart) / 1000
// 2.043,表示首屏加载时间是2.043秒
performance.getEntrier() // 查看每一个资源加载的时间
- navigationStart:表示浏览器开始加载当前文档的起始时间,包括重定向开始的时间。整个导航计时的基准点。
- domLoading:开始解析HTML文档并构建 DOM 树的时间。
- domComplete:记录所有资源(包括图像、样式表、脚本等)加载完毕,DOM树构建完成,且所有 load 事件处理程序待触发的时间。此时
document.readyState
变为"complete"
。- domContentLoadedEventEnd:“DOMContentLoaded” 事件实际触发的时间,此时浏览器已经完成了DOM解析和CSSOM构建,大部分JavaScript脚本可以开始执行。
- loadEventStart: “load” 事件即将被触发的时间,标志着所有资源(包括子框架)已完全加载。
- loadEventEnd:“load” 事件实际触发并执行完成的时间,网页加载过程至此全部结束。
- connectStart:开始建立与服务器TCP连接的时间。这包括SSL/TLS握手(如果有)的时间。
- connectEnd:完成与服务器TCP连接建立的时间。此时,TCP连接已建立,可以开始发送HTTP请求。
- requestStart:发送HTTP请求(包括请求头)到服务器的时间。至此,浏览器完成了所有前期准备工作。
- responseStart:收到第一个字节的HTTP响应的时间。服务器开始返回数据。
- TCP连接建立耗时:connectEnd - connectStart
- 请求发送到接收响应首字节的耗时(网络往返时间): responseStart - requestStart
- 页面渲染准备时间(DOMContentLoaded):domContentLoadedEventEnd - navigationStart
- 完整页面加载时间(load事件):loadEventEnd - navigationStart
按照时间顺序
Object.entries(timing).sort(([, valueA], [, valueB]) => valueA - valueB);
[
[ 'navigationStart', 1713947661293 ], // 表示**浏览器开始加载当前文档的起始时间**,包括重定向开始的时间。整个导航计时的基准点。
[ 'redirectStart', 0 ], // 收到第一个字节的HTTP响应的时间。服务器开始返回数据。
[ 'redirectEnd', 0 ], // 收到完整HTTP响应(包括所有响应头部和正文)的时间。至此,服务器端的响应过程结束。
[ 'fetchStart', 1713947661294 ], // 记录浏览器开始为当前文档请求资源(如发起网络请求或从缓存中读取)的时间。如果资源来自缓存,这个时间可能早于 navigationStart。
[ 'domainLookupStart', 1713947661301 ], // 记录浏览器开始进行 DNS 解析(如果需要)的时间。如果使用持久连接、缓存或不需要 DNS 解析(如 file: 协议或同一源重新加载),则值等于 fetchStart。
[ 'domainLookupEnd', 1713947661301 ], // 记录 DNS 解析完成的时间。如果不需要 DNS 解析,则值等于 domainLookupStart。
[ 'connectStart', 1713947661301 ], // 开始建立与服务器TCP连接的时间。
[ 'secureConnectionStart', 1713947661331 ], // 如果当前连接使用了SSL/TLS协议,记录开始安全连接协商的时间。如果未使用SSL/TLS,值为0。
[ 'connectEnd', 1713947661368 ], // 完成与服务器TCP连接建立的时间。此时,TCP连接已建立,可以开始发送HTTP请求。
[ 'requestStart', 1713947661368 ], // 发送HTTP请求(包括请求头)到服务器的时间。至此,浏览器完成了所有前期准备工作。
[ 'responseStart', 1713947661411 ], // 收到第一个字节的HTTP响应的时间。服务器开始返回数据。
[ 'responseEnd', 1713947661413 ], // 记录浏览器接收到服务器响应的最后一个字节的时间,即整个响应接收完毕。
[ 'domLoading', 1713947661423 ], // 记录浏览器开始解析 HTML 文档并构建 DOM 树的时间。
[ 'domInteractive', 1713947661454 ], // 记录 DOM 树解析完成,脚本执行完毕,且页面处于交互状态(即 document.readyState 变为 "interactive")的时间。
[ 'domContentLoadedEventStart', 1713947661707 ], // 记录 DOMContentLoaded 事件开始触发的时间,此时DOM树已构建完成,样式表已解析完成,但外部脚本可能仍在加载和执行。
[ 'domContentLoadedEventEnd', 1713947661708 ], // 记录 DOMContentLoaded 事件处理程序执行完毕的时间。
[ 'domComplete', 1713947661728 ], // 记录所有资源(包括图像、样式表、脚本等)加载完毕(不包括可能仍在加载的非关键性资源),DOM树构建完成,且所有 load 事件处理程序待触发的时间。此时 document.readyState 变为 "complete"。页面处于可交互状态。
[ 'loadEventStart', 1713947661728 ], // 记录 load 事件开始触发的时间,标志着页面加载过程基本结束。
[ 'loadEventEnd', 1713947661759 ], // 记录 load 事件处理程序执行完毕的时间,标志着整个页面加载周期的正式结束。
]
2 解决方案
异步加载脚本
HTML解析器遇到script标签会暂停渲染过程,将控制权交给JS引擎;JS引擎运行完毕,浏览器把控制权还给渲染引擎,继续CSSOM和DOM的构建;(浏览器碰到JS就交出控制权的原因是不知道JS的内容会不会对接下来的渲染有没有影响)
- 使用async属性让脚本非阻塞渲染流程异步加载;
<script async src="app.js"></script>
- 使用 defer 属性让脚本非阻塞渲染流程异步加载;
<script defer src="app.js"></script>
async 和 defer 的区别是 async 是下载完就执行,加载完script.js,HTML解析暂停,不保证执行顺序。
defer 是在所有元素解析完成之后,再执行;DOMContentLoaded
事件触发之前完成,按照写的顺序执行;
2.1 减少入口文件体积(重要)
入口文件体积主要指的是HTML、CSS和JavaScript等资源文件的初始下载大小。
路由懒加载,解析路由时才会加载组件。
const routes = [
{
path: "Blogs",
name: "ShowBlogs",
component: () => import('./components/ShowBlog.js')
}
];
文本压缩
移除注释、空白字符等非必要内容,减少文件大小;
// Webpack配置示例
optimization: {
minimize: true,
}
2.2 静态资源本地缓存
- 后端返回资源:采用http缓存;
- 前端合理利用localStorage;
- CDN(内容分发网络)来加速静态资源的加载:react、react-dom、react-router-dom、axios;
2.3 UI框架按需加载(重要)
- element-UI、antd按需引入;
import { Button } from 'antd';
2.4 避免组件重复打包(重要)
假设A.js文件是一个常用的库,有多个路由使用A.js文件,这样会造成重复下载;
解决方案:在webpack的config文件中,修改CommonsChunkPlugin的配置 minChunks: 2;
将使用2次及以上的包抽离出来,放进公共依赖文件中,避免重复加载组件;
2.5 图片资源压缩(重要)
- 对于页面上使用的icon,可以使用在线字体图标,或者雪碧图,将众多的小图标合并到一张图上,减轻http请求的压力;
- 使用png格式或者使用tinyPNG等工具压缩图片,在不影响视觉质量的前提下减小文件尺寸。
- 这里要注意:图片懒加载并不能直接减少入口文件体积,但是可以减少首次页面渲染所需要的总下载量;
<img src="image.jpg" loading="lazy" alt="描述文字" />
通过推迟非首屏图片的加载时间,从而加速首页的渲染速度;具体体现在:- 减少初始请求量:减少HTTP请求;
- 优先加载关键内容:确保核心内容可以被优先加载和渲染,而不会被图片的加载过程阻塞;
.sprite-container {
background-image: url('path/to/sprite.png');
}
.icon-example1 {
width: /* 图标宽度 */;
height: /* 图标高度 */;
background-position: /* X坐标 */px /* Y坐标 */px;
}
.icon-example2 {
width: /* 图标宽度 */;
height: /* 图标高度 */;
background-position: /* X坐标 */px /* Y坐标 */px;
}
2.6 开启GZip压缩
拆完包之后,再用gzip做一下压缩,安装compression-webpack-plugin
webpack中配置压缩;
2.7 服务端优化(不属于首页加载,属于加载)
使用Http2协议来减少网络延迟和多路复用请求;