Web性能优化权威指南(读书笔记)
书本开片就阐述了一个很重要的定理:速度是关键
在互联网飞速发展的时代,人们有非常多的选择,大家变的没不那么有耐心了,人们越来越追求速度方面的用户体验。WPO(Web Performance Optimization。web性能用优化)是越来越越多的前端开发所关注的事情。
本书概述了网络技术,无线网络性能,HTTP,浏览器API与协议,从底层上告诉用户Web优化的原理。
造成web缓慢罪魁祸首是延迟。这里的延迟指的是消息从起点到终点经历的时间。这个定义很简单,但是造成延迟的原因很多,任何系统都有可能造成影响传输消息的时间。因此,弄清楚这个因素是什么,是Web性能优化提高的关键。
延迟分为下面几种延迟
1.传播延迟(从发送端发送数据开始,到接收端接收到数据所经过的时间)
2.传输延迟(将消息中的所有比特从发送到全部转移到接收端所用的时间)
3.处理延迟(处理分组首部,检查位错误及确定分组目标所需要的时间。)
4.排队延迟(到来的分组排队等待处理时间)
我们在浏览器的地址栏输入URL地址,然后按下回车,然后得到了我们想要的网址,那么问题来了!
在这个过程中浏览器替我们做了什么?
1.浏览器会检查本地是否有缓存或则web缓存,如果有缓存就直接取缓存。
2.在没有缓存的情况下浏览器会根据域名进行DNS解析,将域名解析成服务器的IP地址,从而得到目标IP(这个步骤耗时客场可长可短,特别是第一次DNS解析时特别长,后面本地都会缓存DNS,下次请求就会直接调用它。)
3.有了IP地址之后,浏览器向客户端与服务器会有三次TCP握手(这里会消耗比较长的时间,每次传输信息都要启动一次TCP的链接,而每次TCP链接都要付出很高的代价),最后形成一条客户端端口到服务器端口的一条TCP链接。
4.TCP链接成立后,浏览器就可以向服务器发送http请求,服务器响应,将客户端需要信息返回给浏览器。
5.浏览器得到资源后,开始渲染页面。浏览器在解析HTML文档的基础上构建DOM,与此同时,还有一个常常被忽略的模型--CSSOM,也会基于特定的样式表规则和资源构建而成。这两个模型共同创建”渲染树”,浏览器根据这个渲染树,去布局页面和并在屏幕上绘制图形,最终成为一个新的页面展示给大家。
在浏览器敲击url 到得到整个页面我需要多长时间呢?
总时间 = DNS解析时间 + 建立TCP链接时间 + 发送http并得到响应的时间 +页面渲染时间。
一切看起来十分的明朗,其实却有非常多的坑。
坑一:DNS解析是需要花时间的,如果页面上的域名多,那么DNS解析查询就花费时间越多,所以页面上的域名越少,解析域名的时间也就越少,那有同学就问了,就用一个域名不就好了嘛 ? 不行!http请求也有个毛病,在一个TCP连接中,只有一个http请求,而客户端最多能够并发打开六个TCP链接,服务器也只能同时处理最多处理六个请求。当服务器同时接收到六个a,b,c,d,e,f http请求,其中a的请求处理最长时间但他是第一个处理的,然后服务器再并行处理bcdef五个请求,这个五个请求很快完成了处理,但a还没处理完,这个时候服务器把后面五个先处理完成的先缓冲起来,等a处理完并发送响应后,再发送bcdef的响应。这样本来bcdef可以早早响应,却因为a的原因而被堵在哪。造成了时间浪费,所以解决方法就是域名分区,减少服务器并行的处理。但说好了减少页面域名的呢?这个就需要开发们在这里面权衡了。
坑二:我们可以把TCP想象成一个管道,http是里面的流水,流水有两种状态,客户端流向服务器,服务器流向客户端。所以这里面就有几种局限,首先客户端发起请求后,服务器才能应答,把需要的东西发给客户端。那么每次请求都会是一次耗时的过程。就像我们向产品要资源一样,我们打电话给产品,产品接电话,知道我需要一个重构稿,然后打开rtx发给我,后来我又打电话给产品,产品接电话,知道我需要一个分享图片,然后打开rtx发给我。 而我做了很多重复的事情,我多打了一次电话,算上等待产品接电话的时间,再加上产品多打开了一次rtx的时间。时间在大量的浪费,多做了许多事情。所以减少打电话的时间,资源能够一次拿完的就一次拿完。同理,页面的http请求越少越好,每一次的http请求都是耗时的。而在页面上,每一个js文件,css文件,图片文件都是一条http请求。所以合并js,合并css,合并图片为雪碧图,减少http请求。
坑三:页面的渲染的过程就是,DOM和CSSOM一起将页面渲染出来。但是这个时候有个捣乱家伙出现了,javascript出现了,脚本执行过程对dom节点的操作会堵塞DOM的解析和构建,类似的js查询对象的计算样式,也会阻塞css的渲染。结果出现了js还没执行完成DOM是无法构建成功的,而js在CSSDOM构建完成之前,也是无法进行的,这样就造成了页面的堵塞。所以必须让css以最快的速度下完,css发到页面最上面,而js放到页面最下面。
优化建议:
1.减少http请求,将js合并,css合成,图片做成雪碧图。考虑小资源(base64编码)嵌入页面(坑二有说明);
2.适当的域名分区,介绍http求情堵塞的情况(坑一有说明)。
3.添加Expire/Cache-Control头。给浏览器一个时间和一个判断:即在一段时间内,如果服务器端的内容没有更新,客户端在请求时就直接使用缓存数据,而不请求服务器内容。一般应用中,我们对静态内容添加Expires,对动态内容设置Cache-Control。当然,假设两者均设置为时间常数的话,前者会被后者覆盖掉
4.将css放在页面最上面(坑三有说明)浏览器解析html的过程:获取html文档及样式表文件;构建dom树和css树。每当有一个新元素加入dom树,浏览器就会通过css选择器查遍css样式表,找到符合该元素的样式应用在这个元素上面,形成render tree。而浏览器对标签的解析是从上到下的,所以css出现的越早越好啊。
5.将js放在页面最下面假 设我们不把script标签放在最后面,不给标签设置defer、async属性,页面解析时候遇见script标签时候,浏览器会这么做:停止渲染,转而发起请求下载这个.js文件(耗时一),下载完之后,会执行这个.js文件(耗时二),一共是两个耗时过程。而在这个过程中,页面窗口的状态是两个字:白板!但是假如我们添加了defer、async属性,浏览器会怎么做呢?
遇见defer立刻下载文件,但是不阻塞后续dom渲染。当dom渲染结束后,立即执行该文件。而且js文件的执行是按顺序执行的,相互之间的依赖还在。
遇见async立即下载文件并且执行,而且也不阻塞后续dom渲染。但是有个不好的副作用:假设相邻的a,b两个js文件,a很大b很小,b依赖”下载并执行“过程发生之后,应该会造成乱序的后果。
看得出来,即使加了defer、async属性,也改变不了js文件立即下载的特性。那为了克服这个问题,就把js丢到文档最后吧。尽快解析dom呈现内容给用户才是王道!
6.压缩css和js代码。
7.避免重定向。