前端⾯试经典题之从输⼊地址到页⾯加载过程中发⽣了什么
  从⽤户输⼊地址到浏览器加载界⾯,主要过程如下:
1. DNS解析
2. TCP连接
3. 发送HTTP请求
4. 服务器接收请求并响应
5. 浏览器解析并进⾏渲染
6. 连接结束
 下⾯进⾏具体过程分析
  ⼀、 DNS解析
  通俗地来讲,DNS解析就是讲⽤户输⼊的站点地址解析成服务器所在的ip地址。⽤户在浏览器中输⼊的
地址并不是该域名真正意义上的地址,⽽要将该地址(譬如www.baidu)解析成ip地址的过程,就是DNS解析。
  DNS解析是⼀个递归查询的过程,这个过程所需要的步骤有点繁杂(有兴趣可⾃⾏百度查询),⽽且存在着多次TCP和UDP请求,⼗分占⽤资源,所以这就涉及到DNS的⼀个知识点 - DNS优化。
  DNS优化⽅法之⼀是使⽤DNS缓存,⼀般可分为:浏览器缓存、系统缓存、路由器缓存、IPS缓存、跟域名缓存、顶级域名缓存和主域名服务器缓存。
  DNS优化的第⼆种⽅法是DNS负载均衡,我们平时所说的CDN(Content Delivery Network)内容分发⽹络,使⽤到的也是DNS负载均衡技术。这个过程中使⽤多台服务器来提供响应,它的原理是当接收到⽤户发送过来的请求时,可以返回⼀个最适合⽤户的IP地址给⽤户(根据⽤户的地理位置或其他影响传输效率的因素分配的),这个过程就是DNS负载均衡,也叫做DNS重定向。
  ⼆、 TCP连接
  通过DNS域名解析后就可以获取到服务器的地址了,接下来就是客户端要与服务器建⽴连接,这个过程是由TCP协议完成的,也就是我们所熟悉的三次握⼿。负载均衡的理解
  第⼀次握⼿:建⽴连接时,客户端发送syn包(syn=x)到服务器,并进⼊SYN_SENT状态,等待服务器确认;
  第⼆次握⼿:服务器收到客户端发过来的syn包,必须确认客户的SYN(ack=x+1),同时⾃⼰也发送⼀个SYN包(syn=y),此时服务器进⼊SYN_RECV状态;
  第三次握⼿:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进⼊ESTABLISHED(TCP连接成功)状态,完成三次握⼿。
  在查阅资料的时候看到⼀个图,似乎可以帮助我们更加轻易地了解三次握⼿的过程,⼤家可以看⼀看:
  当三次握⼿完成后便TCP连接便完成了,客户端可以与服务器进⾏传输数据。
  关于三次挥⼿,这位博主使⽤了更加形象并且贴近⽣活的例⼦来讲解,也可以参考⼀下他的⽂章来帮
助理解:
  三、发送HTTP请求
  在客户端与服务器连接成功之后,客户端要先发送⼀个请求给服务器,告知服务器我要做什么事,需要调⽤什么资源。⼀个完整的HTTP请求报⽂包含三个部分,分别是请求⾏、请求报头、请求正⽂。举个栗⼦:
1 GET/sample.jspHTTP/1.1
2 Accept:image/gif.image/jpeg,*/*
3 Accept-Language:zh-cn
4 Connection:Keep-Alive
5 Host:localhost
6 User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)
7 Accept-Encoding:gzip,deflate
8
9 username=jinqiao&password=1234
  第1⾏为请求⾏,它包含了请求⽅法(GET),URL(sample.jsp),http版本(HTTP/1.1)。其中,常见的请求⽅法由GET、POST、PUT、DELETE、OPTIONS、HEAD。
  第2-7⾏为请求报头,它包括了Accept(指定客户端⽤于接受哪些类型的信息)、Accept-Language(指定可接受语⾔种类)、Accept-Encoding(指定接受的编码⽅式)、Connection(设置为Keep-alive可⽤于告诉客户端本次HTTP请求结束之后并不需要关闭TCP连接,⽅便下次继续使⽤HTTP请求时使⽤相同的TCP通道,提⾼效率)、Host(客户端指定⾃⼰想访问的http服务器的域名/IP 地址和端⼝号)、User-Agent(向访问⽹站提供你所使⽤的浏览器类型及版本、操作系统及版本、浏览器内核、等信息的标识)等等。
  第8⾏为空⾏,表⽰请求报头在这⾥就结束了,这个空⾏不能省略!
  第9⾏是请求正⽂,当⽤户发送请求时需要将⾃⼰的数据发送给服务器,这些数据就存储在请求正⽂当中。
  四、服务器接收请求并作出响应
  与请求报⽂类似,响应报⽂也分为三个部分,分别是状态码、响应头部、响应正⽂。
  状态码主要有以下⼏种:
  1xx:指⽰信息–表⽰请求已接收,继续处理。
  2xx:成功–表⽰请求已被成功接收、理解、接受。
  3xx:重定向–要完成请求必须进⾏更进⼀步的操作。
  4xx:客户端错误–请求有语法错误或请求⽆法实现。
  5xx:服务器端错误–服务器未能实现合法的请求。
  响应头部主要由Cache-Control、 Connection、Date、Pragma等组成。
  响应体为服务器返回给浏览器的信息,主要由HTML,css,js,图⽚⽂件组成。
  五、浏览器进⾏解析并渲染
  客户端在接收服务器传输过来的⽂件之后,便由游览器的引擎开始解析⽂件并在屏幕中渲染出来,其步骤主要如下:
  1. 接收字节,处理HTML并构建出DOM树;
  2. 处理CSS⽂件并构建出CSSOM树;
  3. 将DOM树和CSSOM树结合起来并构成渲染树;
  4. 根据渲染树来布局,并计算出各个元素的⼏何信息;
  5. 在屏幕中渲染像素,并绘制节点。
  详细解析过程可参考:,浏览器渲染流程分析与总结。
  浏览器还没接收到完整的HTML⽂件时,它就开始渲染页⾯了,在遇到外部链⼊的脚本标签或样式标签或图⽚时,会再次发送HTTP请求重复上述的步骤。在收到CSS⽂件后会对已经渲染的页⾯重新渲染,加⼊它们应有的样式,图⽚⽂件加载完⽴刻显⽰在相应位置。在这⼀过程中可能会触发页⾯的重绘或重排。这⾥就涉及了两个重要概念:Reflow(回流)和Repaint(重绘)。
  ⾸先我们需要了解⼀下什么是回流和重绘:
  回流,在元素的内容、结构、位置或尺⼨等发⽣变化时,需要重新计算它的样式和重构渲染树,这个过程就叫reflow,也叫做layout。
  重绘,当元素仅发⽣外观上的改变(如背景⾊、边框颜⾊、⽂字颜⾊等)时,只需要应⽤新的样式⽽不需要修改其CSSOM树和DOM 树,这个过程就叫做repaint。
  通过它们的定义我们可以知道,回流的成本要⽐重绘⾼得多,所以在实际开发过程中,我们应尽量避免回流的发⽣,因为DOM树⾥的每个结点都会有reflow⽅法,⼀个结点的reflow很有可能导致⼦结点,甚⾄⽗点以及同级结点的reflow。
  下⾯列举出⼀些可能会出现回流/重绘的操作:
增加、删除、修改DOM结点时,会导致回流或重绘;
移动DOM的位置,或是做特效动画的时候;
内容发⽣变化; 
修改CSS样式的时候;
Resize窗⼝的时候,或是滚动的时候;
修改⽹页的默认字体时;
  基本上来说,reflow有如下的⼏个原因:
Initial,⽹页初始化的时候;
Incremental,⼀些js在操作DOM树时;
Resize,其些元件的尺⼨变了;
StyleChange,如果CSS的属性发⽣变化了;
Dirty,⼏个Incremental的reflow发⽣在同⼀个frame的⼦树上;
  ⼩拓展:如果使⽤传统的⽅式来修改样式,必定会多次操作DOM树导致资源占⽤率较⾼。⽽vue因为使⽤了虚拟DOM树,它是在虚拟DOM树上模拟做出了所有修改操作之后,再⼀次性更新到DOM树上,所以可以有效地提升效率,避免了多次回流/重绘。
  讲完html解析,下⾯讲⼀下js的解析。
  js的解析是由浏览器中的js解析引擎来完成的。我们都知道js是单线程运⾏的,所有任务必须排队来完成。但有时候⼜可能会有⼀些任务⽐较耗时,所以需要⼀种机制可以先执⾏排在后⾯的任务。所以为了
解决这种情况引⼊了⼀种概念:异步操作(asynchronous)。同步任务就是放在主线程上执⾏的任务,异步任务是放在任务队列中的任务。所有的同步任务在主线程上执⾏,形成⼀个执⾏栈;异步任务有了运⾏结果就会在任务队列中放置⼀个事件;脚本运⾏时先依次运⾏执⾏栈,然后会从任务队列⾥提取事件,运⾏任务队列中的任务,这个过程是不断重复的,所以⼜叫做事件循环(Event loop)。关于异步操作,我会在后⾯写⼀篇详细博⽂来介绍。
  浏览器在解析过程中,如果遇到请求外部资源时,如图像、iconfont、JS等,浏览器将会重复上述过程下载资源。这些请求过程是异步的,并不会影响HTML⽂档进⾏加载;但是当⽂档加载过程中遇到JS、HTML⽂件时浏览器就会挂起渲染程序,要等到⽂档中JS⽂件加载完毕并等待解析执⾏完成,才会继续HTML的渲染过程。其原因是JS有可能修改DOM结构,这就意味着JS执⾏完成前,后续所有资源的下载是没有必要的,这就是JS阻塞后续资源下载的根本原因。CSS⽂件的加载不影响JS⽂件的加载,但是却影响JS⽂件的执⾏,JS代码执⾏前浏览器必须保证CSS⽂件已经下载并加载完毕。
  六、连接结束
  当客户端从服务器那接收完所有数据之后,便会向服务器发送⼀个信号,请求与服务器断开连接,这就是我们常说的四次挥⼿过程。
  它的主要流程如下图: 
  第⼀次挥⼿是浏览器发完数据后,发送FIN给服务器请求断开连接;
  第⼆次挥⼿是当服务器接收到客户端的FIN时,向客户端发送⼀个ACK,其中ACK的值等于FIN+seq;
  第三次挥⼿是服务器向客户端再发送⼀个FIN,告知客户端应⽤程序已关闭;
  第四次挥⼿是当客户端收到服务器发送过来的FIN时,回复⼀个ACK给服务器,其中ACK的值是FIN+seq。
  ⼩拓展1:为什么要进⾏4次挥⼿?
  最简明扼要的答案就是:为了确保数据能够被完整传输。当被动⽅(在本⽂中可理解为服务器)接收到请求断开连接的⼀⽅(在本⽂中可理解为客户端,即浏览器)传输过来的FIN报⽂通知时,它仅仅表⽰主动⽅没有数据再发送给被动⽅了。但未必被动⽅所有的数据都完整的发送给了主动⽅,所以被动⽅不会马上关闭SOCKET,它可能还需要发送⼀些数据给主动⽅后,再发送FIN报⽂给主动⽅,告诉主动⽅同意关闭连接,所以这⾥的ACK报⽂和FIN报⽂多数情况下都是分开发送的。
  ⼩拓展2:为什么连接的时候是三次握⼿,关闭的时候却是四次握⼿?
  因为当服务器收到客户端的SYN连接请求报⽂后,可以直接发送SYN+ACK报⽂。其中ACK报⽂是⽤来应答的,SYN报⽂是⽤来同步的。但是关闭连接时,当服务端收到FIN报⽂时,很可能并不会⽴即关闭SOCKET,所以只能先回复⼀个ACK报⽂,告诉客户端,"你发的FIN报⽂我收到了"。只有等到服务端所有的报⽂都发送完了,我才能发送FIN报⽂,因此不能⼀起发送。故需要四步握⼿。
  总结:
  ⾄此,浏览器从输⼊url地址,到界⾯完成呈现的过程便分析得差不多了,其中包含了很多知识点,⼗分考验应试者的知识⾯,需要花时间将这个过程消化下来。这也是我的第⼀篇博客,参考了前⼈们得出来的经验,并稍作总结,希望能够帮助到像我⼀样正在准备⾯试的⼩伙伴们。
  参考资料:
  理解TCP/IP三次握⼿与三次挥⼿的正确姿势:;
  TCP的三次握⼿与四次挥⼿理解及⾯试题:;
  浏览器渲染流程分析与总结:;
  前端经典⾯试题:从输⼊URl到页⾯加载发⽣了什么:。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。