第1节 理解Web性能
1.1 模拟网络连接
由于是在本地计算机上运行客户网站的,所以向本地主机发出请求不会出现延迟。但没有延迟就很难衡量任何性能提升,因为这种场景下不会存在网络瓶颈。
首先打开Chrome,启用开发者工具。在Windows下需要按F12,在Mac下则要按Command +Alt + I。此时开发者工具应该会出现在Chrome窗口中。另一种办法是选择View ➤ Developer➤Developer Tools(视图→开发者→开发者工具)菜单。出现Tools菜单时,点击窗口顶部的Network选项卡,如图所示。
注意!用完要记得关闭,不然会影响浏览其他网站
1.2 资源瀑布图
在Network选项卡中,首先要确保选中Disable cache复选框。首次访问一个网站时,不会有任何资源缓存——这个场景才是你想要重现的,否则网站的资源将从缓存中提供。尽管有缓存时网站加载速度更快,但最好假设普通用户未曾缓存过你的网站资源。对于这样的未知站点,此类情况发生的概率更大。
在Network选项卡中,要确保左上角的Record按钮处于开启状态(见图1-7)。按钮为红色代表已启用
1.3 ⭐浏览器与服务器通信
- 当浏览器请求网页时,使用超文本传输协议(Http)协议和服务器通信,浏览器发出一个HTTP请求,Web服务器回一个HTTP响应,响应包含状态码和请求的内容
- 发出请求后,会受到一个200 OK 的响应码,这个响应码确认了请求的资源确实存在,且响应中还包含了index.html的内容,随后,Web浏览器会下载并解析index.html的内容
- 上述所有步骤都会产生所谓的延迟:包括等待请求到达Web服务器所花费的时间、Web服务器汇集和发送响应内容所花费的时间,以及Web浏览器下载响应内容的时间。提高性能的主要目的之一就是减少延迟,即减少响应到达客户端所需要的时间。
- 在HTTP/1服务器和浏览器的通信中,可能会出现一种被称为队头阻塞(head-of-line blocking)的现象。之所以会发生这种情况,是因为浏览器限制了单一时间点内发出的请求数(通常是6个)。当一个或者多个请求正在处理,而其余请求已完成时,对内容的新请求将会被阻塞,直到原先剩余的请求完成为止。这种行为会增加页面的加载时间。HTTP/2是HTTP的一个新版本,它在很大程度上解决了队头阻塞问题,并在浏览器中得到了广泛支持
1.4 基本的Web优化技术
1.4.1 优化网站资源(css、js、html)
减少请求数。但请注意,这种方法最适合用于HTTP/1工作流。这个客户网站的请求已经比较轻量了,减少请求数并没有多大作用
这些优化工作包括:首先要缩小网站资源,包括CSS、JavaScript和HTML本身;然后要在不损害其视觉完整性的前提下,优化网站上的图像;最后要在服务器上压缩文本资源。
1.4.2 缩小资源
缩小(minification)是从基于文本的资源中去除所有空白和非必要字符的过程,因而不会影响资源的工作方式。下图是CSS应用缩小的基本思想。
本节首先要缩小网站的CSS,然后是JavaScript,最后是HTML
先下载包
1
npm install -g minifier html-minify
缩小CSS
1
minify -o styles.min.css styles.css
然后在index.html中更新这个文件的引用,方法是将标签的引用从styles.css更改为styles.min.css
1
<link rel="stylesheet" type="text/css" href="css/styles.min.css">
依照上面的方法 缩小Javascript、html文件,之后修改引入即可。
缩小Html
缩小网站的HTML之前,需要将网站根文件夹中的index.html复制到一个名为index.src.html的单独的源文件中,以便保留原始文件并进行更改。复制完成后,可以使用htmlminify将其缩小
1
htmlminify -o index.html index.src.html
1.5 使用服务器压缩
服务器压缩的工作方式是用户从服务器请求网页。用户的请求附带一个Accept-Encoding头部信息,向服务器告知浏览器可以使用的压缩格式
步骤
安装compression模块
1
npm install compression
配置Node HTTP服务器以使用compression
1
2
3
4
5
6
7
8
9var express = require("express");
var compression = require("compression");
var app = express();
// 运行静态服务器
app.use(compression()) //脚本将compression模块挂载到Web服务器
app.use(express.static(__dirname));
app.listen(8080);比较应用服务器压缩前后客户网站上文本资源
1.6 压缩图像
你试过压缩JPEG或MP3文件吗?这不仅不会缩小体积,而且最终的压缩文件可能会更大。这是因为这些类型的文件在编码时已经被压缩了。其压缩方式和Web上的内容没什么不同。要注意避免压缩那些已经在编码时使用压缩的文件类型,例如JPEG、PNG和GIF图像,以及WOFF和WOFF2字体文件。
要压缩这些图像,请将它们上传到TinyPNG网站,该网站将自动进行优化。完成后,下载所有文件,并将其复制到网站的img文件夹。出现提示时,为所有冲突选择Overwrite(覆盖)选项。然后重新加载页面,在Chrome的开发者工具中再次检查瀑布图,以查看这些较小的图像所产生的差异。效果如下:
第2节 使用评估工具
2.1 使用Google PageSpeed Insights
Google PageSpeed Insights (一次只能分析一个URL)
使用Google Analytics进行批量报告
如果你的网站上已经有Google Analytics,那么你要做的就是登录并跟进。如果你尚未在网站上安装它,请使用Google账户登录http://www.google.com/analytics,并按照说明进行操作。这个过程只需花费很少的时间,并且需要将一小段JavaScript代码粘贴到站点的HTML中。之后需要等一到两天,让Google Analytics收集数据。
请注意,向网站添加Google Analytics会带来法律问题。安装跟踪代码时,你要接受法律协议的条款。如果你是网站的唯一拥有者,那么可以自行决定,否则一定要得到网站拥有者的同意。如果你是一家大公司的开发人员,这一点很重要,因为法律审查在大公司是常见的流程。
报告指标
❏ Page——页面URL。
❏ PageViews——报告周期内页面的浏览次数。报告周期通常是前一个月,但可以更改为自定义的时间段。
❏ Avg. Page Load Time——页面加载的平均用时,单位是秒。
❏ PageSpeed Suggestions——PageSpeed Insights为提升相关页面URL的性能,给出的建议数量。单击这个值将跳转到一个新窗口,其中包含该URL的PageSpeed Insights报告。
❏ PageSpeed Score——PageSpeed Insights报告给出的分数。该分数的范围为1~100,分数低表示有改进的空间,分数高表示性能特征好。
2.2 检查网络请求
2.2.1 查看计时时间(首字节时间)
首字节时间(Time to First Byte,TTFB),即从用户请求网页到响应的第一个字节到达之间的时间。
鼠标悬浮在瀑布图(可到1.2了解)中的
waterfall
即可查看。
2.2.2 查看HTTP请求和响应头
典型的请求/响应图,它显示了伴随请求和响应的HTTP头部(尽管该示例比实际中简单得多)
在Network选项卡下,单击资源名称,右侧的单独窗格中将显示其请求和响应头部。
Web服务器的Content-Encoding响应头可以用于确定资源是否已被压缩,以及所使用的压缩算法(本例中为gzip)
2.3 渲染性能检查工具
2.3.1 ⭐理解浏览器如何渲染网页
- 用户访问网站时,浏览器将解析HTML和CSS,并将其渲染到屏幕。图2-15显示了这个过程的基本情况。
- 解析HTML创建DOM(Document Object Model)
- 从Web服务器下载HTML时,浏览器会对其进行解析以构建DOM,这是HTML文档结构的层次表示
- 解析CSS创建CSSOM(CSS Object Model)
- DOM建立完成后,浏览器解析CSS并创建CSSOM。CSSOM与DOM类似,只不过它是用来表示将CSS规则应用于文档的方式。
- 布局元素
- DOM和CSSOM树组合创建渲染树,然后渲染树执行布局过程,在此过程应用CSS规则,并在页面上布局元素以创建UI
- 绘制页面
- 文档完成布局过程后,页面外观将应用CSS和页面中的媒体内容。绘制过程结束时,输出转换为像素并在屏幕上显示。
- 解析HTML创建DOM(Document Object Model)
2.3.2 使用Google Chrome的Performance面板
Chrome的Performance面板可以记录页面的加载、脚本执行、渲染和绘制活动
事件摘要显示会话中上述每个类别花费的CPU时间量。可以在工具窗格底部的Summary选项卡看到摘要
火焰图用来表示计算机程序中发生的事件。在Chrome的Performance面板中,它将这些数据排列在一个调用栈中。对火焰图来说,调用栈是记录的页面活动的分层表示。
当你在火焰图中找到一个想要深入的调用栈时,可以通过点击它的层与之交互。点击层时,Performance面板底部的摘要视图将会更新所选事件的特定信息
2.3.3 jank可能是问题事件元凶
- 最小化浏览器加载和渲染页面的时间。要做到这一点,必须击败唯一的敌人:jank。jank是指交互和动画效果卡顿,或未能顺利渲染。如果使用的编程技术欠佳,那么即使是从网络快速加载的页面,也会受到jank的影响。
- 导致jank的原因时单一的帧中占用了太多的CPU
- 当在活动概述或火焰图上看到红色时,它就是低帧速率的一个指征,这是jank的前兆
2.4 JavaScript代码基准测试
使用
console
的time
和timeEnd
,在代码块前后使用1
2
3
4console.time("Flag")
//...中间测试代码
console.timeEnd("Flag")
//然后在控制台查看即可
2.5 模拟设备和互联网连接(TODO)
第3节 优化CSS
3.1 原则
减少冗余代码
合并原则
避免类名过于具体
1
header div.phoneNumber h3.numberHeader
简化为
1
.numberHeader
3.2 ⭐查找CSS冗余
csscss是一个命令行工具,可以在CSS中查找冗余。这是重构CSS的一个好起点。要安装csscss,需要使用Ruby的gem安装程序。如果你安装了SASS,即可使用gem
你可以在一个CSS文件上运行它。尝试在客户网站的styles.css文件上运行:
1
csscss styles.css -v --no-match-shorthand
这条命令使用两个参数检查styles.css是否有多余的规则。-v参数告诉程序要详细打印出匹配的规则。–no match-shorthand参数使程序不会将任何简写规则(如border-bottom)扩展为更明确的规则(如border-bottom-style样式)。如果要扩展这些规则,请删除这个开关。程序输出将显示跨元素间的所有冗余样式。以下代码是这些规则的一个示例。控制台输出如下:
根据控制台输出执行如下操作
合并选择器和规则
清除单个选择器中的匹配规则——返回代码前面,并将#okayButton、#schedule和.submitAppointment a多余的规则移除。
重新运行csscss,检查输出,并重复前面的步骤——清理完旧选择器中的冗余规则后,重新运行csscss,验证优化后的规则是否已从代码中删除。
3.3 em与rem
- em是根据文档的默认字体大小(通常为16px)计算的相对单位。公式:px / 默认文字大小 = em。此时,平板计算机的临界点600px,除以默认的文档字体大小16px,得到的值就是37.5em。1000px的桌面临界点使用相同的公式转换,得到的值就是62.5em。
- em是特定于上下文的单位
- 如果其父级元素的字体大小为12px,则em值是通过将原始px值除以12来计算的。rem单位类似于em,只是它的上下文总是依据文档根节点的默认字体大小,而不是其父元素的字体大小。
- rem单位类似于em,只是它的上下文总是依据文档根节点的默认字体大小,而不是其父元素的字体大小
3.4 viewport
为了确保设备正确显示新的响应式CSS,还应该在
元素中添加以下标签:1
<meta name="viewport" content="width=device-width,initial-scale=1">
这个标签告诉浏览器两件事:设备应该以与设备屏幕相同的宽度渲染页面,并且页面的初始比例应该是100%
3.5 调整CSS性能
3.5.1 原生CSS中避免使用@import
你可能见过@import指令在CSS中的使用。应该避免这种做法,因为@import指令与标签不同,在下载整个样式表之前,不会处理样式表中的@import指令。这种行为会导致网页的总加载时间延迟。
@import串行请求
在LESS/SASS中,@import有不同的功能。在这些语言中,@import由编译器读取并用于打包LESS/SASS文件。这样你就可以在开发期间模块化样式,并在编译为CSS时进行打包。
<link>
标签加载是并行加载请求
3.5.2 防止无样式内容闪烁
- 出现这种原因是由于css在文档太晚加载,应该尽早在
<head>
标签中添加css引用,这样还可以提高页面渲染性能
3.5.3 使用flex布局替代传统布局,性能更优
3.6 使用CSS过渡
3.6.1 trasition
使用
1
transition: transition-property transition-duration transition-timing-function transition-delay;
这个简写属性代表以下内容。
transition-property——需要设置动画的CSS属性。值可以是任何有效的属性,如color、border-radius等。某些属性无法设置动画,例如display属性。
transition-duration——完成过渡所需的时间。可以用秒或毫秒表示(例如,2.5s或250ms)。
transition-timing-function——过渡期使用的缓动效果。可以使用预设(如linear或ease)表示,也可以使用steps函数分段,或者通过cubic-bezier函数提供更细微的缓动行为。忽略此选项将使用默认的ease预设设置过渡动画。
transition-delay——过渡开始前的延迟时间(以秒或毫秒为单位)。如果不需要延迟,则忽略此项。还可以在元素上过渡多个属性。如果还希望过渡.box元素的宽度和高度,则可以向transition属性添加更多内容:
还可以在元素上过渡多个属性。如果还希望过渡.box元素的宽度和高度,则可以向transition属性添加更多内容:
1
.box{ width:64px; height:64px; transition:width 2s ease-out, height 2s ease-out;}
3.6.2 will-change优化过渡
will-change接受任何有效的CSS属性,或者以逗号分隔的属性列表,用来设置动画
1
will-change:property,...
需要注意的是需要给属性足够的时间工作
1
2
3
4
5//error
#sideHeader a:hover{
background-color:#ff0000;
will-change:background-color;
}这样做的问题是,浏览器没有时间来应用必要的优化。此时要想更好地使用该属性,则应当将其应用于父元素的:hover状态,以便浏览器可以预测将要发生的情况:
1
2
3
4//good
#sideHeader:hover a{
will-change:background-color;
}这为浏览器提供了足够的时间来为元素的更改做准备,因为当用户的鼠标进入#siteHeader元素并悬停在链接上时,其中的所有a元素都将在#siteHeader元素悬停事件时准备好。
关于这个属性,需要记住的关键一点是,你可以预测元素的潜在更改,而不是假设它们会发生。