前端面试最为经典的问题:输入URL到页面加载完成都发生了什么

1 前言

这个可以说是前端面试的最为经典的问题。它不但考察知识面的广度,而且考察深度。而且它层次性,无论是大牛还是小白都能做出针对性的回答。

Q&A:
Q:网络上已经由这么多关于这个问题的博客,你为什么还要再写?
A:我的小学语文老师经常说:好记性不如烂笔头。我的学习经验证明:如果一个复杂的问题,你不去整理或者实践,那么你不能指望:看过答案之后就掌握怎么解决这个问题。

另外:我对网络上关于这个问题的回答稍微做了整理。

  • 这个文章从键盘输入开始谈起,很极客,偏向底层:这里

  • 图文并茂,用户友好:这里

  • 老外的文章,很严谨:这里

2 正文

DNS解析

所谓DNS域名解析过程,就是将域名,例如www.google.com,解析为IP地址的过程。

后面会讲到的TCP协议和HTTP协议的通信过程中不能缺少IP地址。

好了,我们正式开始。当我们输入URL,DNS域名解析的过程就开始了,浏览器会先后访问下列地方:

浏览器缓存

浏览器会缓存DNS记录持续一定时间。有趣地是,操作系统并不告诉DNS记录有效的事件,所以浏览器缓存的这些记录有效一定的时间间隔:不同的浏览器时间间隔不同,大约在2-30分钟。

在chrome,通过这个地址:chrome://net-internals/#dns 访问chrome的DNS缓存

操作系统缓存

如果浏览器缓存没有包含需要的记录,浏览器用一个系统调用(Linux的说法)从操作系统获取它的缓存。

系统缓存主要存在/etc/hosts(Linux和Mac系统)中:

Win10系统可以用 ipconfig /displaydns命令(dos命令)获取DNS缓存(其他版本window未验证)。

路由器缓存

路由器也具有存储DNS缓存的功能

ISP DNS缓存

ISP也就是Internet Service Provider,翻译成中文就是互联网服务提供商,在天朝就是电信,联通,移动这些了。

ISP提供了本地DNS服务器,用于提供DNS缓存服务

递归搜索

下图是该过程的一个例子:

前端面试最为经典的问题:输入URL到页面加载完成都发生了什么

上图中的例子中,我们要访问www.wikipedia.org这个域名。

接下来,我们要访问根域名服务器198.41.0.4。(全球有13组根域名服务器。)。如果根域名服务器内不存在相应DNS记录,则会返回.org*域名服务器的地址:204.74.112.1。

浏览器得到回复后,会然后访问.org*域名服务器,如果该域名服务器没有相应的DNS记录,那么会返回wikipedia.org域名服务器的地址:207.142.131.234。

浏览器然后访问wikipedia.org域名服务器,如果之前一直没有得到DNS记录,那么这时候就应该得到了。

TCP三次握手

在发起HTTP请求之前,我们需要建立TCP连接,关于三次握手的理解和实践请看:这篇博文

HTTP请求

前端面试最为经典的问题:输入URL到页面加载完成都发生了什么

你能够确定Facebook的主页不能够通过缓存获取。所以,浏览器会发送HTTP request给Facebook的服务器。

服务器针对浏览器的HTTP request,会有相应的reponse。

当然,这里会涉及HTTP的知识,比如请求头,回复头,状态码等等。这里先不赘述。

浏览器解析网页

浏览器获取到HTTP response(一般是一个HTML文件),浏览器的内核开始解析HTML。在解析HTML的过程中,如果它需要请求其他资源,比如图片,比如CSS层叠样式表,比如JS文件,那么浏览器会继续发送HTTP请求。

在解析HTML的过程中,浏览器两个比较重要的事务。

一是生成DOM树,HTML代码中的一个标签就是一个DOM节点,DOM节点的嵌套关系组成了DOM树。

二是在DOM树基础上,根据DOM节点的集合属性(margin,padding,width,height等)生成render树。

注意,颜色,背景色等css属性并属于render树的范畴。之所以要将margin,padding,width这些集合属性与其他属性区分开来,需要根据所有DOM节点的这些属性计算各个DOM节点的位置。

如果任一DOM节点的集合属性发生变化,所有DOM节点的位置都要重新计算一遍,也就是说,要重新生成render。

生成render树的过程被称为reflow,译作回流。

浏览器会在render树的基础上继续渲染颜色、背景色、字体等样式,这个过程被称为repaint,译作重绘。

关于reflow和repaint可以看这里

上述过程可以用下图表示:

前端面试最为经典的问题:输入URL到页面加载完成都发生了什么

断开TCP连接

自HTTP1.1协议之后,HTTP就完全支持持久连接,也就是只要建立一次TCP连接,就可以不断发送HTTP请求。

如果浏览器一段时间内不发送HTTP请求,那么浏览器利用reset(RST)报文快速释放已经完成数据交互的TCP连接,以提高业务交互的效率。(为了并发处理HTTP请求,一般会有浏览器会有多个端口和服务器建立TCP连接。)最终会只剩下一个TCP连接,而且reset报文不需要服务器确认。

RST报文详见这篇博文

前端面试最为经典的问题:输入URL到页面加载完成都发生了什么

从上图中可以看到,序号为103-106的TCP报文分别是4个端口向服务器的80端口发送RST报文,释放TCP连接。

最终浏览器只剩下50276端口,50276端口在断开连接,需要不断向80端口发送keep-Alive报文,该报文的目的是告诉服务器:“我可能还要发送HTTP请求哦,不要断开连接哦。“

序号107-118的TCP报文就是keep-Alive报文以及服务器的确认报文,由于这期间一直没有HTTP请求,50276端口不再继续发送keep-Alive报文。

由于之后服务器的80端口一直没有收到keep-Alive报文(持续大约几分钟),服务器开始发送断开连接的请求。TCP的四次挥手正式开始。

序号119-122的TCP报文就是四次挥手的报文。下图对四次挥手报文进行了清晰的阐述,我就不赘述了。

前端面试最为经典的问题:输入URL到页面加载完成都发生了什么

另外:当客户端收到服务器的确认报文(seq = a +1)后,就断开连接,但是服务器要等到发出确认报文(seq = a + 1)之后再等上两个TCP报文周期后才断开连接。这是因为如果客户端没收到确认报文,那么会重发要求断开的报文(seq = b)。

值得注意的是:客户端也可以主动断开连接,但是我还不知道是在什么情况下。

TCP断开连接的内容就阐述完了。这也意味着这个经典问题的结束。

以上。