文章转载自:从输入URL到页面加载完成的过程当中都发生了什么事情html
为何会想要了解从输入URL到页面加载完成的过程当中都发生了什么事情这个问题呢,由于课程参考资料的Web 建站技术中HTML、HTML五、XHTML、CSS、SQL、JavaScript、PHP、ASP.NET、Web Services 是什么中最高票答案中给出了下图所示的网站访问基本过程,张秋怡学姐的解答也十分易懂: 面试
再者这个问题可谓是常见的面试题之一,而这张图中只是给出了很是基本的一个先后端交互的过程,因为本身有基础,因此列出的相关概念也都基本理解了,因而就花些时间扩展一下数据库
咱们在打开浏览器,而后在输入URL
的时候有没有发现浏览器会给你一些你似曾相识且与你输入的内容相匹配的网址呢?其实咱们在浏览器中输入URL
的时候,浏览器就会开始智能的匹配可能URL
,浏览器会从历史记录,书签等地方,找到你已经输入的字符串可能对应的URL
,而后给出智能提示segmentfault
在输好URL后咱们会按下Enter键,浏览器会发起请求,若是URL是域名而不是IP地址,将进行域名解析,所谓域名解析是指什么呢?windows
IP地址是网络上标识站点的数字地址,为了方便记忆,采用域名来代替IP地址标识站点地址,域名解析就是域名到IP地址的转换过程。后端
域名解析按下面的步骤进行(部份内容涉及到计算机网络知识):浏览器
C:\Windows\System32\drivers\etc
)文件,做用是将一些经常使用的网址域名与其对应的IP地址创建一个关联“数据库”。通常来讲,系统会首先自动从hosts文件中寻找对应的IP地址,若是有的话就直接使用hosts文件里面的IP地址,而后直接进行端口确认DNS
服务器的一个客户,把待解析的域名放在DNS
请求报文中,以UDP用户数据报的方式发给本地DNS
服务器DNS
服务器查找到相应的域名的IP地址,就把对应的IP地址放在回答报文中返回递归查询: 在该模式下DNS服务器接收到客户机请求,必须返回一个准确的查询结果给客户机。若是该DNS服务器本地没有存储被查询的DNS信息,那么该服务器会(替客户机)询问其余服务器,并将返回的查询结果再返回给客户机。缓存
迭代查询: 在该模式下DNS服务器接收到客户机请求,若是该DNS服务器本地没有存储被查询的DNS信息,DNS服务器会向客户机提供其余可以解析查询请求的DNS服务器地址,让客户机再向这台DNS服务器提交请求,依次循环直到返回查询的结果为止。服务器
浏览器获得IP地址后,还要确认一下端口,默认端口是80端口,一个服务器可能会提供不一样的服务,这些服务经过端口来区分,能够指定端口号网络
浏览器获得IP地址并确认端口后,会向目标服务器发起HTTP请求,HTTP请求是经过TCP链接来发送的(若是是HTTPS则须要先创建SSL链接,再是TCP链接,下面的讨论基于HTTP),具体以下
通俗的能够理解为:
A主动向B打电话:嗨,能听到吗(SYN=1,seq=x),而后A就开始等待B的回答(SYN-SENT状态),此时A不知道B能不能听到
B听到A的话以后,能够确认它能听到A,可是它还要确认一下A能不能听到他本身的声音,因而B说:我能听到你的声音(ACK=1,ack=x+1),你能听到个人声音吗(SYN=1,seq=y),而后B开始等待A的恢复(SYN-RECD状态)
A听到B的话以后,A能够确认两件事,一是B能听到它说话,二是它也能听到B说话,A已经能够随时说话和倾听了(ESTABLISHED状态)。可是此时的B还在等待中,并不知道A能不能听到,因此此时A须要再回复B说:我能够听到你的声音(ACK=1,ack=y+1),开始愉快的聊天吧~(seq=x+1),B听到这句话后便也能够随时说话和倾听了(ESTABLISHED状态)
以后两我的就能够balabalabala....
有一种观点是三次握手是基于TCP协议的可靠性(
Reliability
)要求,这是确认双发都能进行收发的最小次数,两次确认不了,四次多余。可是并无彻底意义上的可靠,不论握手多少次都只能代表握手的时候是可靠的,不能保证后面数据传输时一直可靠,由于信道是不可靠的,固然三次握手至少能够代表它曾经可靠,这是两次握手没法完成的,而四次甚至更屡次握手仅仅是提升“它曾经可靠”这个结论的可信程度。因此这个握手也只是确保可靠的一个基本须要,TCP协议的可靠性(注意区分完整性integrity
)更多的是由校验和、定时器超时重传、确认机制.
在《计算机网络》一书中也有讲过这个问题,给出的解释是:三次握手是为了防止失效的链接请求报文段被服务端接收,从而产生错误。具体例子以下所述:
client
发出的一个链接请求报文段并无丢失,而是在某个网络结点长时间的滞留了,以至延误到链接释放之后的某个时间才到达server
。原本这是一个早已失效的报文段。但server
收到此失效的链接请求报文段后,就误认为是client
再次发出的一个新的链接请求。因而就向client
发出确认报文段,赞成创建链接。- 假设不采用**“三次握手”**,那么只要
server
发出确认,新的链接就创建了。可是因为如今client
并无发出创建链接的请求,所以不会理睬server
的确认,也不会向server
发送数据。而server
却觉得新的链接已经创建,并一直等待client
发来数据。这样,server
的不少资源就白白浪费掉了。- 采用**“三次握手”**的办法能够防止上述现象发生。例如刚才那种状况,
client
不会向server
的确认发出确认。server
因为收不到确认,就知道client
并无要求创建链接
一样通俗的解释一波:
A对B要传的文件已经传完了,因而他对B说:我要传的文件已经传完了,我要准备下线了(seq=u,FIN=1)。而后A就等待B的回复(FIN-WAIT-1状态)
B看到A的消息后,回复A说:知道了,可是我还有文件给你(ACK=1,ack=u+1,seq=v)。B进入等他文件传完的状态(CLOSE-WAIT状态)。A收到B的回复以后,下线不了了,因而继续等待着B的文件传完(FIN-WAIT-2状态)
几分钟后,B的文件传完了,此时他对A说:个人文件传完了,我也要下线了(seq=w,FIN=1,ACK=1,ack=u+1),而后B等待A的回复来确认真的能够下线了(LAST-ACK状态)
A收到B的回复后,便对A说:好的,那你下线吧(ACK=1,seq=u+1,ack=w+1)。此时A会等待一段时间(2MSL,TIME-WAIT状态),B收到后就直接下线了(CLOSE状态),而后2MSL时间到了以后,A也下线(CLOSE状态)
扩展知识小课堂:
当服务器B收到断开链接的请求时,服务器可能仍然有数据未发送完毕,因此服务器先发送确认信号,等全部数据发送完毕后再赞成断开
由于TCP链接是全双工模式,服务器B收到A的断开请求时,仅仅代表A没有东西传给服务器B了,但此时服务器B可能向A的传输还没结束,因此服务器B要先给A一个确认收到A的断开请求的ACK报文,而后继续向A把信息传完,等传完以后服务器B再向A发送断开请求的报文段,等A收到并回复ACK报文后再释放链接。
也就是说对于A来讲他要发送请求给B并等待B确认,对于B来讲也要发送请求给A并等待A确认,二者都通过这两个过程才能彻底释放TCP链接,而非单方面的释放。 创建链接只须要创建,没有数据的影响,而释放链接还要考虑数据是否传输完,因此创建链接的时候B确认收到A的创建请求与B发送创建请求这一步能够合成一步成为TCP创建链接的第二次握手,而释放链接时却必须分开。
2MSL
?首先解释一下MSL,MSL是指最长报文段寿命,RFC793建议为两分钟,但实际上可据实际状况而定,也就是说一个报文段最久可存在的时间是MSL
1xx: 表示通知信息的,好比请求收到了或正在处理
2xx:表示成功,操做被成功接收并处理
3xx:表示重定向,通常完成请求还必须采起进一步的行动
4xx:表示客户端的差错
5xx:表示服务器的差错
若是响应可缓存,浏览器将把响应存入缓存
浏览器根据HTTP报头信息解码响应,决定如何处理这些响应,并展示响应,以响应为一个HTML
为例 浏览器开始自上而下,自左而右的加载HTML
文档,最开始会遇到 <!DOCTYPE>
声明,而后根据<!DOCTYPE>
声明浏览器就知道该用哪一种规范来解析这个文档
再继续边加载边解析,边生成DOM树,加载过程当中遇到外部CSS文件,浏览器便会另外发出一个请求,来获取CSS文件(过程和上面说的同样),获取CSS后会生成CSS Rule
树。DOM树和CSS Rule树生成Render树,页面能够开始边加载边渲染了
<head>…</head>,display=none
的元素)不会被插入渲染树中;还有像一些节点是绝对定位或浮动,这些节点会在文本流以外,所以他们会在渲染树和DOM树的不一样位置,渲染树标识出真实的位置,并用一个占位结构标识出他们原来的位置,而DOM树上是他们原来的位置layout
)和"绘制"(paint
)这两个步骤,所谓"布局"是指给出每一个DOM节点在浏览器窗口中的准确位置,"绘制"是指遍历Render树将布局好的DOM节点绘制在屏幕上。<script>
标签,浏览器会当即执行(暂不考虑defer及async属性),此时会出现页面阻塞,不只要等待文档中JS文件下载加载完毕,还要等待JS解析执行完毕,才能够恢复HTML文档的加载解析。
Reflow
(称为回流或者重排)<script>
放在的<head>
中,则<body>
标签没法被加载,那么页面天然就没法渲染了,所以这将致使在该JS代码彻底执行完以前,页面都是一片空白,用户体验很是很差,通常我看到长时间的空白页面,我都很是想直接关闭它。所以会推荐将全部<script>
标签尽量放到<body>
标签的底部,以尽可能减小对整个页面下载的影响,此时虽然还会存在一个脚本阻塞另外一个脚本的问题,可是用户体验比上面的好不少,由于用户看到了大部份内容,而不是空白DOMContentLoaded
事件触发以前完成,执行顺序为出现的前后顺序。(高程中指出现实中不必定会按照顺序执行,也不必定会在DOMContentLoaded
事件触发以前完成,所以最好只包含一个延迟脚本,这多是与浏览器的实现有关,具体什么状况下会出现我还不知道???)load
事件触发以前执行,但可能会在DOMContentLoaded
事件触发以前或以后执行。基于前面所说的一点缘由,异步脚本最好不要修改DOM,若是由多个异步脚本,它们之间最好没有依赖关系原本只是想了解了解,结果一入深似海,看似简单的操做背后藏着数不清的小动做,文中也只是涉及了一部分,还有不少相关的过程没有涉及到,可是能力有限,仍是慢慢来,暂时就先告一段落,文中若有错误还请指正哦~