网站性能优化实践
加载过慢导致的白屏、计算耗时太久导致响应不及时或卡顿,都会降低用户对网站的评价。为了提高网站的性能,我们需要分析网站从加载到最终呈现、以及用户操作的响应的过程中,究竟发生了什么。
1. 使用工具衡量性能
在开始进行优化之前,需要强调一点是:必须以真实统计的数据为依据,优化过程中必须看妨碍性能的关键指标是否发生了变化。
PageSpeed Insights 是由 Google 提供的一个检测网站性能的工具,输入网站地址后它会返回网站性能的得分,以及具体改善性能的建议,可以看到它提供了在 移动设备 和 桌面设备的不同评分,可以针对不同设备来做具体的优化。
上图可以看到性能的评分为40分,然后有 首次内容渲染、首次输入延迟 以及 实验室数据等多项统计数据,其中绿/橙/红分别代表了优/一般/差的表现。同时它还提供了优化建议和诊断结果,有助于用户改善网站性能。在随后的部分,我们会逐步解释各个指标、优化建议分别代表什么含义。
Chrome DevTools 作为最重要的网页开发调试工具,几乎能查看到网页加载使用过程的一切信息,作为开发者有必要熟练运用开发者工具。
上图可以看到很多信息,包含了FPS/CPU/Networks/Frames/Interactions/Timing,我们先选中Main这一项,可以看到统计了5.67s内的监测数据,底部面板呈现了在Loading、Script、Renddering等阶段的耗时。将底部的Tab切换到Event Log,并且将Scripting和Rendering取消勾选,可以看到各个时间点发生的事件,下图截取了一部分:
最头部的 Send Request 和 Receive Response 成功请求获取到了HTML的内容,然后在parseHTML中,解析出了对更多资源的加载,于是又触发了更多新的请求,Finish Loading 事件则标志着某个资源的加载的结束。
这里只是一个开头,后续就要开始介绍影响性能的两个途径,即:优化关键渲染路径、优化代码书写方式。借助于上述的工具,我们能够很好的衡量网站在具体指标上的表现。
2. 优化关键渲染路径
2.1 关键渲染路径
关键渲染路径 简单来说就是浏览器将HTML、CSS和JavaScript转化为可见的像素的过程。这个过程包含如下几个步骤:
网页的第一请求个是 HTML 请求,请求到达服务器后,服务器处理并且返回响应,客户端收到响应后开始进行处理,最后进行展示和布局,对应的过程为:
- request
- loading
- response
- scripting:parse,DOM Tree,CSSOM Tree,Render Tree
- rendering:layout
- painting: paint
在 scripting 阶段,HTML parsing 过程创建了 DOM(document object model)Tree,遇到任意链接的外部资源(比如样式文件、js文件、图片文件),浏览器都会发起一个新的请求。
浏览器会持续不断进行 parsing 的过程构建 DOM,发送获取资源的请求,直到最终结束以后,它开始构建 CSSOM(CSS object model)。在 DOM 和 CSSOM 都完成了,浏览器会构建好 Render Tree,计算所有可见内容的样式。
在 rendering 阶段,Render Tree 构建好以后,开始进行 Layout 操作,它决定元素放置的位置和大小。
等这一切结束以后,在 painting 阶段,网页通过称为被 paint 的步骤被绘制出来。
2.2 资源的阻塞问题
关于关键渲染路径过程,非常重要的一点是,一些资源的请求是阻塞性的。这里先列举一般性的结论:
- HTML资源最先加载,其他资源依次并行加载,完成时间和加载顺序无关,和网络、文件大小有关。
- JS的加载,会阻塞HTML parse 和 CSS render;JS的执行按照标签出现的顺序执行。
- CSS的加载,会阻塞HTML parse 和 JS 执行;CSS render需要整个文件加载解析完成,CSS render的顺序和标签的出现顺序相同。
资源并行加载
文件加载通常先出现的标签先加载,但并不串行,即它们的过程可同时进行。结果就是一些比较大的文件虽然先加载,但可能后加载完成。
// html-CRP-block.html
<head>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script src="link-jquery.js"></script>
<link rel="stylesheet" href="bg-color.css"></link>
</head>
<body>
<p>Hello, CRP!!!</p>
</body>
//link-jquery.js
console.log('jquery download and executed ? ' + (!!$ ? 'yes' : 'not ye'));
//bg-color.css
p {
background: red;
}
我们用 Chrome Devtools 的 Performance 记录下来网络情况(如下图),首当其冲的是 HTML 内容,然后是本地的 link-jquery.js
和 bg-color.css
文件,虽然 jquery-3.4.1.js
先出现但是却后开始加载,也是后开始完成。
JS 的按照加载顺序执行
如下为 console 中的输出结果,可见虽然js后面的先加载完,但是执行顺序还是严格依赖出现顺序的。
jquery download and executed ? yes
JS 的加载解析阻塞 HTML/CSS 的解析
// html-CRP-block.html
<head>
<link rel="stylesheet" href="bg-color.css"></link>
</head>
<body>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script src="link-jquery.js"></script>
<p id="hello">Hello, CRP!!!</p>
</body>
//link-jquery.js
console.log(document.getElementById('hello'));
如上代码中,我们可以在 console 中看到的输出结果为 null,说明 JS的加载执行过程,block 了 HTML 的解析,因为直接查询 DOM Tree 是没有该结构的。
//bg-color-red.css
p {
background: red;
}
//bg-color-green.css
p {
background: green;
}
// html-CRP-block.html
<body>
<p id="hello">Hello, CRP!!!</p>
<link rel="stylesheet" href="bg-color-red.css"></link>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<link rel="stylesheet" href="bg-color-green.css"></link>
</body>
稍微修改代码,将 Devtools 的网络调整到 Slow 3G
,刷新界面可以看到背景色首先是红色,然后过了数秒后变成绿色。
同理,我们可以通过 Devtools 的 Performance 看到,最先加载的蓝色区域是HTML内容,两个紫色的CSS文件都早于jquery加载完成,但是一直等到jquery加载和执行完成以后,才会继续parseHTML、Parse StyleSheet,并且最终触发DOMContentReady事件,因此 JS的加载同样也阻塞 CSS 的解析和渲染。
CSS 的加载
CSS文件的加载是加载和解析同步进行的,但只有等到整个CSS文件都被解析好,才会绘制CSSOM并且完成绘制,这是因为CSS文件中属性是可以相互覆盖的,加载部分就进行渲染无疑会降低性能。
同样如下例子可以看到,界面长时间处于白色背景,然后才出现红色背景,和无padding的body,可见 CSS 的绘制,同样按照标签的出现顺序进行绘制。
// html-CRP-block.html
<body>
<p id="hello">Hello, CRP!!!</p>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="bg-color-red.css"></link>
</body>
上述例子在网页中的效果是,先看到文字
CSS 的加载对 HTML/JS 的影响
//bg-color-red.css
p {
background: red;
}
// html-CRP-block.html
<body>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<p id="hello">Hello, CRP!!!</p>
<script src="link-jquery.js"></script>
<link rel="stylesheet" href="bg-color-red.css"></link>
</body>
网页中打开上述HTML可以看到,首先是页面空白,并且console中没有输出,然后过了数秒,才会出现红色背景的文字区域。
打开分析工具录制,可以看到蓝色的HTML先加载、然后是link-jquery.js、background-red.css先完成(虽然bootstrap.css先加载),在bootstrap.css加载完后,先Parse Stylesheet,然后继续 Parse HTML、Evaluate Script、Recalculate Style,可见 CSS的加载和解析也会阻塞HTML的解析 和 JS的解析执行。
2.3 如何优化关键渲染路径
在关键渲染路径的什么阶段做优化,并没有绝对的规则,一切都要以工具衡量的结果为出发点。
我可以把阻塞的类型简单分为:阻塞加载、阻塞执行、阻碍渲染。
浏览器的parsing过程的,
2.4 项目中进行的实践
// package.json
"scripts": {
"generate": "webpack --config webpack.generate.js --profile --json > stats.json",
"analyze": "webpack-bundle-analyzer --port 8888 stats.json"
}
"devDependencies": {
"webpack-bundle-analyzer": "^3.6.0",
}
devSever 环境下,请求的资源大小 Top 5
总计 16.16M
- echarts 2.46M
- elemenet-ui 1.82M
- xlsx.js 1.35M
- zrender/lib 488KB, refered by echarts
- lodash.js 466KB
- mediaelement 321KB
- jquery.js 298KB
(1)echarts+zrender/lib,仅在项目中绘制了一个 chart。
(2)loadash只引用到了4个方法 upperFirst、camelCase、debounce、sizes。
(3)jquery只用到了extend方法。
可以通过覆写上述方法后,或者寻找替代方案后,将对应工具库从项目中移除。
尝试将(1)(3)移除后,再执行 analyze
总计 13.91M,减少的大小正好等于 echarts、zrender/lib、jquery.js 的大小。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 网站性能优化
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论