从输入地址到显示页面的过程,大致可以分成两个部分:
第一部分:用户输入在浏览器地址栏输入URL → 到客户端(浏览器)拿到服务端(服务器)的数据
第二部分:浏览器拿到数据后 → 渲染呈现页面给用户(浏览器工作过程)
例如:
第一部分:
第一步: 输入网址https://www.jianshu.com/p/8f050df1961d
可以把URL分成协议、网络地址、资源路径三部分。
- 协议:从该计算机获取资源的方式,有HTTP、HTTPS、FTP等,不同协议有不同的通讯内容格式。
- 网络地址:指连接网络上的哪一台计算机,可以是域名、IP地址,可以包括端口号。如:“www.jianshu.com”、“192.168.0.91:8080”。
- 资源路径:指从服务器上获取哪一项资源。如 “/p/8f050df1961d” 。
第二步:通过DNS解析获得网址对应的IP地址
- 浏览器缓存 – 浏览器会缓存DNS记录一段时间。 有趣的是,操作系统没有告诉浏览器储存DNS记录的时间,这样不同浏览器会储存个自固定的一个时间(2分钟到30分钟不等)。
- 系统缓存 – 如果在浏览器缓存里没有找到需要的记录,浏览器会做一个系统调用(windows里是gethostbyname)。这样便可获得系统缓存中的记录。
- 路由器缓存 – 接着,前面的查询请求发向路由器,它一般会有自己的DNS缓存。
- ISP DNS 缓存 – 接下来要check的就是ISP缓存DNS的服务器。在这一般都能找到相应的缓存记录。
- 递归搜索 – 你的ISP的DNS服务器从跟域名服务器开始进行递归搜索,从.com顶级域名服务器到Facebook的域名服务器。一般DNS服务器的缓存中会有.com域名服务器中的域名,所以到顶级服务器的匹配过程不是那么必要了。
DNS中递归查询和迭代查询的区别:
1、 递归查询: 一般客户机和服务器之间属递归查询,即当客户机向DNS服务器发出请求后,若DNS服务器本身不能解析,则会向另外的DNS服务器发出查询请求,得到结果后转交客户机。
2、 迭代查询(反复查询): 一般DNS服务器之间属迭代查询,如:若DNS2不能响应DNS1的请求,则它会将DNS3的IP给DNS2,以便其再向DNS3发出请求。
以一个DNS请求解析为例:
1)用户发起域名请求到dnsA,这时dnsA有这个记录,将结果返回给用户,这个过程是递归查询。
2)用户发起域名请求到dnsA,这时dns没有这个记录,它去向dnsB问有没有这个记录,以此类推,直到把结果返回给用户,这个过程是递归查询。
3)用户发起域名请求到dnsA,这时dnsA没有这个记录,它告诉用户,我没有这个记录,你去问dnsB吧,这个过程是迭代查询。
第三步:浏览器与远程web服务器 通过TCP三次握手协商来建立一个 TCP/IP 连接
在通过DNS域名解析后,获取到了服务器的IP地址,在获取到IP地址后,便会开始建立一次连接,这是由TCP协议完成的,主要通过三次握手进行连接。
- 第一次握手: 建立连接时,客户端发送SYN(synchronize)包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;
- 第二次握手: 服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
- 第三次握手: 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
- 完成三次握手,客户端与服务器开始传送数据。
在这个过程中,如果发送端在规定延迟时间内没有收到回复则默认接收方没有收到请求,而再次发送,直到收到回复为止。
第四步:浏览器 通过TCP/IP连接 向web服务器 发送一个 HTTP 请求
HTTP请求包括请求报头和请求主体两个部分,其中请求报头包含了至关重要的信息,包括请求的方法(GET / POST)、目标url、遵循的协议(http / https / ftp…),返回的信息是否需要缓存,以及客户端是否发送cookie等。
第五步:服务器响应请求
服务接收到客户端发送的HTTP请求后,查找客户端请求的资源,并返回响应报文,响应报文中包括一个重要的信息——状态码。状态码由三位数字组成。
常见的状态码
1xx 【消息】服务器收到请求,需要请求者继续执行操作
2xx 【成功】请求已成功被服务器接收、理解、并接受。
3xx 【重定向】客户端需要采取进一步的操作以完成请求
4xx 【客户端请求错误】客户端错误,请求包含语法错误或无法完成请求
5xx 【服务器错误】服务器在处理请求的过程中发生了错误
常见的有:
200 OK //客户端请求成功
304 Not Modified // 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized // 当前请求要求用户的身份认证
403 Forbidden // 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found //请求资源不存在,输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable // 由于超载或系统维护,服务器暂时的无法处理客户端的请求。一段时间后可能恢复正常
第六步:服务器返回相应文件
请求成功后,服务器会返回相应的HTML文件。接下来就到了页面的渲染阶段了。
第二部分:
第七步:页面渲染
整个过程涉及两个方面:解析和渲染。在渲染页面之前,需要构建DOM树和CSSOM树。
在浏览器还没接收到完整的 HTML 文件时,它就开始渲染页面了,在遇到外部链入的脚本标签或样式标签或图片时,会再次发送 HTTP 请求重复上述的步骤。在收到 CSS 文件后会对已经渲染的页面重新渲染,加入它们应有的样式,图片文件加载完立刻显示在相应位置。在这一过程中可能会触发页面的重绘或重排。这里就涉及了两个重要概念:Reflow和Repaint。
Reflow,也称作Layout,中文叫回流,一般意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树,这个过程称为Reflow。
Repaint,中文重绘,意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如,背景色,边框颜色,文字颜色等),此时只需要应用新样式绘制这个元素就OK了,这个过程称为Repaint。
所以说Reflow的成本比Repaint的成本高得多的多。DOM树里的每个结点都会有reflow方法,一个结点的reflow很有可能导致子结点,甚至父点以及同级结点的reflow。
下面这些动作有很大可能会是成本比较高的:
- 增加、删除、修改DOM结点时,会导致Reflow或Repaint
- 移动DOM的位置,或是搞个动画的时候
- 内容发生变化
- 修改CSS样式的时候
- Resize窗口的时候(移动端没有这个问题),或是滚动的时候
- 修改网页的默认字体时
- 基本上来说,reflow有如下的几个原因:
- Initial,网页初始化的时候
- Incremental,一些js在操作DOM树时
- Resize,其些元件的尺寸变了
- StyleChange,如果CSS的属性发生变化了
- Dirty,几个Incremental的reflow发生在同一个frame的子树上
第八步:关闭TCP连接(四次挥手)或者继续保持链接
第一次挥手是浏览器发完数据后,发送FIN请求断开连接。
第二次挥手是服务器发送ACK表示同意,如果在这一次服务器也发送FIN请求断开连接似乎也没有不妥,但考虑到服务器可能还有数据要发送,所以服务器发送FIN应该放在第三次挥手中。
这样浏览器需要返回ACK表示同意,也就是第四次挥手。
浏览器内核——厂商前缀——代表浏览器——内核背景
- Triden -ms- IE浏览器系列 该内核程序在1997年的IE4中首次被采用,是微软在Mosaic代码的基础之上修改而来的,并沿用到IE11,也被普遍称作”IE内核”。Trident实际上是一款开放的内核,其接口内核设计的相当成熟,因此才有许多采用IE内核而非IE的浏览器(壳浏览器)涌现。
- Gecko -moz-Firefox Netscape6开始采用的内核,后来的Mozilla FireFox(火狐浏览器)也采用了该内核,Gecko的特点是代码完全公开
- Webkit -webkit- Safari内核,Chrome内核原型,开源,包含了来自KDE项目和苹果公司的一些组件,主要用于Mac OS系统,它的特点在于源码解构清晰、渲染速度极快,缺点是网页代码的兼容性不高,导致一些编写不标准的网页无法正常显示
- Blink -webkit- Chrome、opera等除IE、Firefox、Safari之外的几乎- 所有浏览器(几乎所有国产双内核浏览器(Trident/Blink)如360、猎豹、qq、百度等) Blink是一个由Google和Opera Software开发的浏览器排版引擎,是基于Webkit内核的子项目