大致流程:
1.域名解析
首先在浏览器中输入域名,例如输入 www.baidu.com
浏览器开始查找域名的IP地址,用户发起请求→操作系统把域名发送给本地区的域名服务器→如果有解析完成返回IP,结束
2.发起TCP的3次握手
TCP三次握手:
浏览器获得 IP 地址后,就会对目标服务器发起建立 TCP 连接的请求,建立连接主要有三个步骤,一般称为客户端与服务器端的三次握手:
第一次握手: 建立连接时,客户端发送syn包(syn=j){同步序列编号,是TCP/IP建立连接时使用的握手信号}到服务器,并进入SYN_SENT状态,等待服务器确认;
第二次握手: 服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手: 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
3.建立TCP连接后发起http请求
TCP三次握手建立连接成功后,客户端按照指定的格式开始向服务端发送HTTP请求,服务端接收请求后,解析HTTP请求,处理完业务逻辑,最后返回一个具有标准格式的HTTP响应给客户端。
4.服务器端响应http请求,浏览器得到html代码
处理HTML标记,构建DOM树。
处理CSS标记,构建CSSOM(CSS对象模型)树。
将DOM树和CSSOM树融合成渲染树(会忽略不需要渲染的dom)。
根据渲染树来布局,计算每个节点的几何信息。
在屏幕上绘制各个节点。
中间遇到各种资源时,会进行资源的下载
5.浏览器解析html代码,并请求html代码中的资源(JS+CSS+img等)
解析HTML文件,从head开始,然后是body
如果头部中由外部的CSS链接,就去下载CSS样式表,如果有js链接就去下载JS脚本文件
解析body部分,生成DOM树,同时浏览器主进程下载CSS
CSS文件下载完成,解析CSS构建CSSOM树,结合DOM树合并成RenderObject(渲染对象)树
html解析->外部样式、脚本加载->外部样式执行->外部脚本执行->html继续解析->dom树构建完成->加载图片->页面加载完成
6.断开TCP连接
TCP四次挥手:
客户端或服务器均可主动发起挥手动作
第一次挥手: 主动关闭方,将FIN置为1,Seq设置为Z为上一次对方传送过来的Ack值,Ack设置为X为Seq值+1。设置好以上值后,将数据发送至被动关闭方(这里标记为:B)。然后A进入FIN_WAIT_1状态。
第二次挥手:B收到了A发送的FIN报文段,向A回复,Ack设置为第一次挥手中的Seq值+1,Seq设置为Y第一次挥手中的Ack值。然后B进入CLOSE_WAIT状态,A收到B的回复后,进入FIN_WAIT_2状态。
第三次挥手:B再次向A发送报文,将FIN置为1,Ack设置为X,Seq设置为Y。然后B进入LAST_ACK状态,A收到B的报文后,进入TIME_WAIT状态。
第四次挥手:A收到B发送的FIN报文段,Ack设置为Y,Seq设置为X。然后A进入TIME_WAIT状态,B在收到报文后进入CLOSED状态,A在发送完报文等待了2MSL时间后进入CLOSED状态。
7.浏览器对页面进行渲染呈现给客户
对于以上过程,要怎样进行性能上的优化呢?可以有以下几点:
一、尽量减少HTTP请求:
1.合并脚本和样式文件,可以把多个CSS文件合成为一个,把多个JS文件合成为一个
2.CSS Sprites 利用 CSS background 相关元素进行背景图绝对定位,把多个图片合成一个图片。
二、使用浏览器缓存
在用户浏览网站的不同页面时,很多内容是重复的,比如相同的JS、CSS、图片等。如果我们能够建议甚至强制浏览器在本地缓存这些文件,将大大降低页面产生的流量,从而降低页面载入时间。
根据服务器端的响应header,一个文件对浏览器而言,有几级不同的缓存状态。
1、服务器端告诉浏览器不要缓存此文件,每次都到服务器上更新文件。
2、服务器端没有给浏览器任何指示。
3、在上次传输中,服务器给浏览器发送了Last-Modified或Etag数据,再次浏览时浏览器将提交这些数据到服务器,验证本地版本是否最新的,如果为最新的则服务器返回304代码,告诉浏览器直接使用本地版本,否则下载新版本。一般来说,有且只有静态文件,服务器端才会给出这些数据。
4、服务器强制要求浏览器缓存文件,并设置了过期时间。在缓存未到期之前,浏览器将直接使用本地缓存文件,不会与服务器端产生任何通信。
我们要做的是尽量强制浏览器到第四种状态,特别是对于JS、CSS、图片等变动较少的文件。
三、使用压缩组件
IE和Firefox浏览器都支持客户端GZIP,传输之前,先使用GZIP压缩再传输给客户端,客户端接收之后由浏览器解压,这样虽然稍微占用了一些服务器和客户端的CPU,但是换来的是更高的带宽利用率。对于纯文本来讲,压缩率是相当可观的。如果每个用户节约50%的带宽,那么租用来的那点带宽就可以服务多一倍的客户,并且缩短了数据的传输时间。
四、图片、JS的预载入
预载入图像最简单的方法是在 JavaScript 中实例化一个新 Image() 对象,然后将需要载入的图像的 URL 作为参数传入。
function preLoadImg(url) {
var img = new Image();
img.src = url;
}
可以在登录页面预载入JS和图片
五、将脚本放在底部
脚本放在顶部带来的问题,
1、 使用脚本时,对于位于脚本以下的内容,逐步呈现将被阻塞
2、 在下载脚本时会阻塞并行下载
放在底部可能会出现JS错误问题,当脚本没加载进来,用户就触发脚本事件。要综合考虑情况。
六、将样式文件放在页面顶部
如果样式表任在加载,构建呈现树就是一种浪费,样式文件放在页面底部可能会出现两种情况:
1、 白屏
2、 无样式内容的闪烁
七、使用外部的JS和CSS
将内联的JS和CSS做成外部的JS、CSS。减少重复下载内联的JS和CSS。
八、切分组件到多个域
主要的目的是提高页面组件并行下载能力。但不要跨太多域名,建议采用2个子域名。
九、精简JS
可以做到两个级别
1、精简:从代码中移除不必要的字符以减少其大小,
2、混淆:在精简的同时,还会改写代码,函数、变量名被转换成更短的字符串
可以使用ShrinkSafe来精简JS http://shrinksafe.dojotoolkit.org/
十、精简CSS
从代码中移除不必要的字符以减少其大小,
可以使用CSS Compressor http://www.cssdrive.com/index.php/main/csscompressor /
十一、精简图片、Flash
对大图片、Flash,要在效果和大小之间做出平衡