Steve Sounders在《高性能网站建设指南》一书中,提出了12条原则指南。
- 尽量减少HTTP请求
- 使用CDN
- 静态资源使用Cache
- 启用Gzip压缩
- JavaScript脚本尽量放在页面底部
- CSS尽量放在页面顶部
- 避免使用CSS表达式
- 减少内联的CSS、JavaScript,尽可能使用外部的CSS、JavaScript文件
- 减少DNS查询
- 精简JavaScript
- 避免重定向
- 删除重复脚本
下面我将就以上12点,以What、Why和How的角度一一进行讲解。
1. 尽量减少HTTP请求
每一个web页面的打开,都不止一个HTTP请求。我们使用Chrome浏览器打开调试窗口,可以看到除了页面doc的请求,还有很多XHR(ajax异步数据)请求,图片、样式表、JavaScript脚本的请求。
虽说现在我们使用的web浏览器都是多线程的,但是过多的HTTP请求还是会拉长白屏时间,拖慢响应速度。
- 我们可以使用webpack技术,将一些用到的JavaScript或css进行合并打包,达到减少HTTP请求的目的。
- 渲染列表页面的时候,列表条目可以通过异步获取,但一次获取1-3页的内容即可,没必要一条一条的获取。
- 同时一些后端逻辑数据也是可以进行合并的。
2. 使用CDN
CDN = Content Delivery Network(内容分发网络)。CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。
对于内容类的网站,如新闻资讯、论坛等,就特别依赖CDN技术。这些网站的内容具有以下特点:
- 内容是由编辑发表或用户发布的内容,而非静态写死;
- 内容的呈现是需要通过计算而成,但变化频率很低;
目前大部分CDN供应商都提供了多线路(移动、联通、电信等)多城市(北京、杭州、青岛等节点)的覆盖。用户访问网站看到的数据,其实都是当地或附近城市的CDN节点缓存的内容,并非来自于网站的真实服务器。这样,即使你的服务器在北京,深圳的用户访问也丝毫没有延迟上的感觉,CDN可以让我们忽略地理差异。
通过CDN还能有效降低服务器的负载,服务器有了更多余量,可以提供更多其他的服务或合理控制服务器规模,以节约这部分的成本。
- CDN是有偿服务,一般提供包年或包量的套餐。越是线路,城市覆盖到位的CDN服务,其价格越是昂贵。
- 目前国内主流的CDN提供商有:阿里云、腾讯云、又拍云等等。
- 我们可以根据自身的内容,计算每个页面的平均大小。可以通过一些网站统计工具如Alexa计算自己网站的每用户平均浏览数量UV。然后可以大致的估算出可以交给CDN处理的数据的大小。
3. 静态资源使用Cache
静态资源指的是网页上用到的图片、css、JavaScript脚本等数据,这些数据并非通过动态网页技术(如PHP、Java)生成的。
每一个网页上的每一张图片(或其他静态资源),也需要发送HTTP请求。如果没有使用CDN服务,或CDN被穿透了,那么这些请求就会落到真实的服务器上。每一个请求过来,服务器都会开一个进程来进行处理,这样势必会增加服务器的负载。
服务器使用Web Server,经过路由规则匹配和查找,访问到磁盘上对应的物理文件,将其读取到内存之后,再通过Web Server才能以HTTP响应的形式,返回给访问页面的浏览器。
通过启用Web Server的Cache功能,可以节约磁盘寻址,读取物理文件的步骤,请求到达Server之后,就能直接返回,可以有效的减少响应时间。
如何开启
Nginx是支持静态文件的缓存的,可以对特定目录,特定后缀名启用缓存,并设置失效时间。配置如下:
location = /content{
proxy_cache cache;
proxy_cache_key $scheme$proxy_host$request_uri;
proxy_cache_valid 200 304 12h; #200和304头信息过期时间12小时
proxy_cache_valid any 10m; #其他过期时间10分钟
add_header Nginx-Cache "$upstream_cache_status";#增加一个头信息
}
#如果url中包含以下路径参数,那么 cookie_nocache 的值为1
if($request_uri ~^/(url3|login|register|password\/reset)){
set $cookie_nocache 1;
}
proxy_cache :指定使用哪个共享内存区域存储缓存键和相关信息;
proxy_cache_key :设置缓存使用的key,默认为访问的完整URL,根据实际情况设置缓存key;
proxy_cache_valid :为不同的响应状态码设置缓存时间;如果是proxy_cache_valid 5s 则200、301、302响应将被缓存;
4. 启用Gzip压缩
GZIP最早用于UNⅨ系统的文件压缩。我们在Linux中经常会用到后缀为.gz的文件,它们就是GZIP格式的。
HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。
当有人来访问服务器中的网站时,这个功能就将网页内容压缩后传输到来访者的浏览器中并显示出来。一般对纯文本内容可压缩到原大小的40%。这样传输就快了,效果就是你点击网址后会很快的显示出来。
测试对比
css
原始大小: 44 KB
压缩后: 10 KB
压缩比: 77.27%
js
原始大小: 6 KB
压缩后: 2 KB
压缩比: 66.67%
某php页面
原始大小: 62 KB
压缩后: 15 KB
压缩比: 75.81%
虽然上面只是随机测试的几个数据,但很明显,使用了gzip压缩后文件的确小了很多。对于手机端浏览器或APP而言,体验也会好很多。
如何开启
Nginx 的 ngx_http_gzip_module 也提供了开启 GZIP 压缩的方式,有下面的一些常用配置:
# 开启
gzip on;
# 压缩等级,1-9。设置多少可以参考:http://serverfault.com/questions/253074/what-is-the-best-nginx-compression-gzip-level
gzip_comp_level 2;
# "MSIE [1-6]\." 比如禁止 IE6 使用 GZIP
gzip_disable regex ...
# 最小压缩文件长度
gzip_min_length 20;
# 使用 GZIP 压缩的最小 HTTP 版本
gzip_http_version 1.1;
# 压缩的文件类型,值是 [MIME type](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types)
gzip_types text/html;
Nginx 上开启 GZIP 之后,理论上会按照 GZIP 配置打开压缩。那如何检测是否开启成功了呢?
image image打开浏览器,访问你的网站,看 Chrome 的 Network,点 use larger request row,如果 Size 上有两个不一样大小的体积(如:222KB 和 613KB),则代表 GZIP 已经成功开启。
5. JavaScript脚本尽量放在页面底部
我们先梳理一下,一个页面的加载渲染流程是:
- 浏览器下载HTML,并获取里面用到的其他资源的地址;
- 浏览器开启多线程去并行下载css,脚本,图片等静态资源;
- 浏览器对HTML做渲染。
常规来说,2和3是并行的。也就是浏览器会一边下载图片和样式,一边先渲染HTML骨架,再将下载好的样式和图片做局部渲染。
如果javascript脚本放在页面顶部,且恰好你的脚本会改变dom结构,那么浏览器会暂时挂起,直到脚本全部下载完毕才会开始渲染。这也是为什么有些网站往往会白屏很久就是打不开,一旦你忍受不了,点了浏览器的停止加载按钮,页面就会立刻显现的原因。
所以建议的格式是:
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://xxx.cn/css/detail.min.css">
</head>
<body>
</body>
<script type="text/javascript" src="http://www.cn/js/jquery.min.js" />
</html>
6. CSS尽量放在页面顶部
道理同上,即保证浏览器能够一边下载css,一边渲染HTML结构。通过减少白屏时间,合理利用浏览器的多线程特性,增加渲染效率。
(未完待续)
网友评论