当前位置: 首页 > Web前端 > HTML

前端面试是必须的!浏览器从输入URL到显示页面做了什么?

时间:2023-04-02 15:12:36 HTML

为什么输入网址后可以显示想要的页面?浏览器在秘密做什么?前端可以针对这些做哪些优化?最近在准备面试的时候,很怕被面试官问到这个问题。浏览器究竟做了什么?你去问浏览器(尴尬)。想一想,还是系统地学习一下,总结一下吧。话不多说,看图吧!可以看出,从输入URL到完成浏览器显示大致可以分为5个阶段:DNS解析TCP阶段HTTP阶段解析/渲染阶段布局布局/渲染页面DNS解析浏览器会先解析域名再发起一个http请求,找到ip地址。这个过程就是dns解析。解析过程如下:1)浏览器首先检查hosts文件中是否有该域名对应的ip地址,如果有则直接向该ip地址发起http请求。如果找不到查询,请继续执行下一步。2)浏览器向本地DNS服务器发送DNS解析报文进行域名解析。本地DNS服务器收到请求后,首先查询缓存,判断是否有对应的记录。如果有,则返回这条记录。步。3)本地DNS服务器在缓存中没有找到对应的记录,于是本地DNS服务器向DNS根服务器发起查询请求。DNS根服务器收到请求后,通过查询获取顶级域名对应的顶级域服务器的IP地址,然后向本地DNS服务器发送响应报文。4)本地DNS服务器收到响应报文后,获取顶级域服务器的地址,然后向该地址发送请求域名解析的DNS请求报文。5)顶级域名服务器收到请求后,首先检查缓存中是否有对应的记录,有则返回对应的记录。如果没有找到,则查询该域名对应的二级域名服务器地址,然后将该地址返回给本地DNS服务器。6)本地DNS服务器收到响应报文后,获取到二级域服务器的地址,然后向该地址发送请求域名解析的DNS请求报文。7)二级域服务器收到请求后,首先检查缓存中是否有对应的记录,有则返回对应的记录。如果没有找到,则查询该域名对应的三级域名服务器地址,然后将服务器地址返回给本地DNS服务器。8)本地DNS服务器收到响应报文后,获取到三级域名服务器的地址,然后向该地址发送请求域名解析的DNS请求报文。9)三级域服务器收到请求后,在DNS区域数据库中查询相应的记录,并返回相应的记录。10)本地域名服务器收到三级域名服务器后,返回一个DNS响应报文给用户,并将这条记录保存在缓存中11)浏览器获取域名对应的ip地址,然后就可以发起http请求。在TCP阶段,看看下面三个概念:ACK:TCP协议规定只有ACK=1时才有效,还规定连接建立后所有发送报文的ACK必须是1个SYN(SYNchronization:用于在建立连接时同步序号。当SYN=1,ACK=0时,表示这是一条连接请求报文。如果对方同意建立连接,则应在响应消息中设置SYN=1和ACK=1。因此,将SYN设置为1表示这是一个连接请求或连接接受消息。FIN(finis):End,终止的意思,用来释放一个连接。当FIN=1时,表示本段发送方的数据已经发送完毕,需要释放连接。上面介绍了tcp的3次握手和4次握手过程。在http连接之前,需要tcp的3次握手,让client和server相互确认,这样才能安心的进行数据传输。经过上面HTTP阶段的复杂通信,两端终于可以说话了。通常,HTTP报文包括客户端向服务器的请求报文和服务器向客户端的响应报文。在浏览器中查看一个http请求,包括3个部分:1.Generalheader1)generalheaderfield包括请求和响应报文都支持的headerfields。2)RequestURL:请求的URL地址3)RequestMethod:请求方法,get/post/put/...4)StatusCode:状态码,200表示请求成功5)RemoteAddress:路由地址2、请求头1)Accept:告诉WEB服务器它接受什么媒体类型,*/*表示任意类型,type/*表示该类型下的所有子类型;2)Accept-Charset:浏览器声明它接受的字符集Accept-Encoding:Browse浏览器声明它接受的编码方式,通常指定压缩方式,是否支持压缩,支持什么压缩方式(gzip,deflate)3)Accept-Language:浏览器声明它接受的语言。语言和字符集的区别:中文是一种语言,中文有很多字符集,如big5、gb2312、gbk等。4)Authorization:当客户端收到WEB服务器的WWW-Authenticate响应时,这个头以自己的认证信息响应给WEB服务器。5)Connection:表示是否需要持久连接。关闭(告诉WEB服务器或代理服务器完成对本次请求的响应后断开连接,不再等待本次连接的后续请求)。keep-alive(告诉WEB服务器或代理服务器完成对本次请求的响应后保持连接,等待本次连接的后续请求)。6)Referer:发送请求页面URL。浏览器向WEB服务器指示它从哪个网页/URL获取/点击当前请求中的网址/URL。7)User-Agent:浏览器表明其身份(是哪个浏览器)。8)Host:发送请求页面的域。9)Cache-Control:浏览器应该遵循的缓存机制。no-cache(不缓存实体,现在请求从WEB服务器上取)max-age:(只接受Age值小于max-age值,且没有过期的对象)max-stale:(可以acceptpastobjects,butTheexpirationtimemustbelessthanthemax-stalevalue)min-fresh:(接受新鲜生命周期大于其当前Age和min-fresh值之和的缓存对象)10)Pramga:主要使用Pramga:no-cache,相当于Cache-Control:no-cache。11)Range:浏览器(如Flashget多线程下载)告诉WEB服务器要抓取对象的哪一部分。12)表单:一个请求标头,给出控制用户代理的人类用户的电子邮件地址。13)Cookie:这是最重要的请求头信息之一3.响应头1)Age:当代理服务器用自己缓存的实体响应请求时,用这个头来表示该实体从生成到现在已经过去了多长时间是时候了。2)Accept-Ranges:WEB服务器表示是否接受请求获取其实体之一的一部分(如文件的一部分)。bytes:表示接受,none:表示不接受。3)Cache-Control:服务器应该遵循的缓存机制。public(可以用缓存的内容响应任何用户)private(只能用缓存的内容响应之前请求过该内容的用户)no-cache(可以缓存,但只有通过WEBserver)max-age:(本次响应中包含的对象的过期时间)ALL:no-store(不允许缓存)4)Connection:是否需要关闭持久连接(连接已经关闭)。keepalive(保持连接,等待此连接的后续请求)。Keep-Alive:如果浏览器请求保持连接,这个header表示你希望WEB服务器保持连接多长时间(以秒为单位)。例如:Keep-Alive:3005)Content-Encoding:WEB服务器指示它使用什么压缩方法(gzip,deflate)来压缩响应中的对象。例如:Content-Encoding:gzip6)Content-Language:WEB服务器告诉浏览器它响应的对象的语言。7)Content-Length:WEB服务器告诉浏览器它响应的对象的长度。例如:Content-Length:260128)Content-Range:WEB服务器表示响应中包含的部分对象是整个对象的哪一部分。例如:Content-Range:bytes21010-47021/470229)Content-Type:WEB服务器告诉浏览器它响应的对象类型。例如:Content-Type:application/xml10)Expired:WEB服务器指示实体何时过期。对于过期的对象,只有在与WEB服务器验证其合法性后,才能用于响应客户的请求。11)Last-Modified:WEB服务器考虑对象的最后修改时间,如文件的最后修改时间、动态页面的最后生成时间等。12)Location:WEB服务器告诉浏览器你要访问的对象已经移动到另一个位置,所以去header指定的位置去获取。13)Proxy-Authenticate:代理服务器响应浏览器,要求其提供代理认证信息。14)服务器:WEB服务器,表示是什么软件,版本。15)Refresh:指示浏览器应在多长时间后刷新文档,以秒为单位。解析/渲染过程浏览器是在解析的同时构建渲染树的过程,渲染引擎会尝试尽快显示内容。它不会等到所有HTML都被解析后才创建和布置渲染树。在处理后续内容时,它会先显示处理过的部分内容。1.DOM树构建首先,浏览器解析HTML文件构建DOM树。Parser模块主要负责解析HTML页面,完成从HTML文本到HTML语法树再到文档对象模型树(DOMTree)的映射过程。2.css解析CSS文件解析完成后,会下载CSS构建渲染树。遇到图片等资源,也会同步下载,不会阻塞html树的构建。但是由于图片占据了一定的区域,影响了后续段落的排列,浏览器需要回过头来重新渲染这部分代码(rearrange/redraw)。CSS解析过程类似于HTML解析,浏览器使用自己的解析器进行解析。一般解析过程是自上而下的,将CSS文件解析成StyleSheet对象,每个对象包含CSS规则。CSS规则对象包含选择和声明对象,以及其他与CSS语法对应的对象。CSS解析完成后,会生成一个大致如下结构的CSSRuleTree。css解析过程:3.加载js的时候遇到js,情况就复杂了。当遇到script标签时,浏览器暂停解析(不暂停下载),将控制权交给JavaScript引擎(解释器)。因为在js中会有对dom的操作,操作完成后会触发重排/重绘,所以继续解析是没有意义的。如果标签引用了外部脚本,则下载脚本,否则直接执行,执行后将控制权交给浏览器渲染引擎。如果将上述方法放在外部js脚本中,则在解析script标签时,html解析会停止6秒。CSS文件的加载不会影响JS文件的加载,但是会影响JS文件的执行。浏览器必须确保在执行JS代码之前已经下载并加载了CSS文件。见下图html解析过程:4.异步加载jsscript提供了2个异步加载js属性:async:HTML5新属性,用于异步下载脚本文件,下载后立即解释执行代码。Dom解析在下载的时候不会阻塞,但是在执行的时候会阻塞。defer:如果script标签设置了该属性,浏览器会开启一个新的线程去下载脚本文件,不会影响后续DOM的渲染;如果有多个defer-setscript标签,则全部按顺序执行;延迟脚本将在文档呈现之后和调用DOMContentLoaded事件之前执行。DomContentLoaded事件只关注HTML是否解析,不关注异步脚本。如果在script标签中包含defer,那么这段脚本不会影响HTML文档的解析,而是在HTML解析完成后才会执行。而DOMContentLoaded只有在defer脚本执行结束后才会被触发。5.构建渲染树渲染的主要流程分为——RenderTree(渲染树)生成——Layout(布局)——Paint(绘图)。DOM树和CSS树结合生成RenderTree(渲染树)——这是一种由视觉元素按照其显示顺序组成的树状结构,是文档的可视化表示,其作用是让浏览器渲染页面正确的顺序元素。Firefox称之为“框架”,而Webkit的术语是渲染器或渲染对象。渲染树与DOM元素是一一对应的,但并不是所有元素都是一一对应的,例如:1、非可视元素不会出现在渲染树中,比如“head”元素,2、如果元素的display属性值为“none”,不会出现在渲染树中(但visibility属性值为“hidden”的元素会出现在渲染树中)。布局/渲染渲染树不包含位置和大小信息。计算这些值的过程就是布局或重排。布局过程是一个递归过程,从根元素开始,递归遍历部分或全部渲染树结构,为每个需要显示的元素计算几何信息。一般根元素的位置坐标为(0,0),大小为浏览器窗口的可见区域。这里涉及到两个重要的概念reflow和repaint:repaint(重绘):元素的某一部分属性发生变化,如字体颜色、背景颜色等,但大小不变。此时发生的变化过程就是重绘。reflow(回流):因为浏览器渲染是一个自上而下的过程,当发现有一部分变化影响了布局,就需要回过头来重新渲染。这个过程称为回流。回流几乎是不可避免的。现在一些常用的效果,比如折叠和展开树状目录(本质上是显示和隐藏元素)等,都会引起浏览器回流。鼠标悬停、点击……这些行为只要引起页面上某些元素的占用区域、定位方式、边距等属性发生变化,就会引起其内部、周围乃至整个页面的重新渲染.基本上,有几种原因会导致回流:1、网页初始化。2、JS在操作DOM树时,添加、删除元素等。3、部分元素的大小发生变化。4.CSS属性的变化,但是浏览器很聪明。为了避免小的变化,它会重绘或回流。浏览器采用的是“脏”系统,会把这些变化批量累积起来,然后做回流。它被称为异步回流或增量异步回流。但在某些特殊情况下,不会这样做,例如:调整窗口大小,更改页面的默认字体等。对于这些操作,浏览器会立即回流。但有时,我们自己的脚本会阻止浏览器这样做,例如,当我们请求以下值时:)在IE中,或者currentStyle等,如果我们的程序在运行时需要这些值,那么浏览器就需要返回最新的值给我们,而这会执行当前累积的操作,造成频繁的reflow或者repaint。减少reflow/repaint的方法通常reflow比repaint耗时更多,也会影响性能,所以在写代码的时候,尽量避免过多的reflow或repaint。减少reflow/repaint的方法:1.不要一个一个地修改样式。建议先定义CSS样式的class,然后直接修改元素的className。2、不要把循环中DOM节点的属性值作为循环变量。3.对动画HTML元素使用固定或绝对位置,然后修改它们的CSS将不会回流。4.离线修改DOM。比如设置DOM的显示:none,然后进行你需要的多次修改,然后显示出来,或者克隆一个节点到内存中,然后随意修改,修改完成后再和线上交换.5.切勿使用表格布局,一个小改动可能会导致整个表格重新布局。渲染页面在绘制阶段,系统会遍历渲染树,调用渲染器的“paint”方法将内容显示在屏幕上。同样,和布局过程类似,也分为全局和增量两种性能优化。1.提高HTML加载速度-精简页面,删除不必要的注释,空格,将嵌入的JS和CSS移动到外部文件,使用压缩工具等-减少文件数量,减少页面引入的文件数量可以减少请求的数量,可以合并的JS和CSS文件尽量合并。-减少域名查询、DNS查询和域名解析耗时,减少对外部JavaScript、CSS、图片等资源的引用,不同域名的使用越少越好。-使用缓存重用数据。-优化页面元素的加载顺序。-使用现代CSS和有效标签。-指定图片的大小。如果在浏览时可以立即判断出图片的大小,就不需要重新布局操作了。-根据浏览器类型选择合适的策略。-使用压缩工具等-页面精简,去除不必要的注释,空格,将嵌入的JS和CSS移动到外部文件,使用压缩工具等2.编写合理的CSS首先,解释一下CSS选择器的匹配顺序,从右到左边!从右到左!从右到左!(重要的事情说三遍),所以,类似“#navli”,我们认为简单的规则应该是立即匹配,但是需要从右往左匹配,所以我们会先搜索所有的li,然后判断其父元素是否为#nav。因此,编写合理的CSS也可以提高我们页面的性能:-DOM的深度尽可能浅,嵌套不宜太深。-减少内联javascriptcss的数量。-使用有效的CSS属性。-不要为ID选择器指定类名或标签名。-避免后代选择器,尽可能使用子选择器。-避免通配符。三、关于javascript标签对于javascript标签,首先要了解它的加载和执行特点:1.加载后立即执行;把所有的javascript标签放在页面的底部,就在body标签关闭之前,以保证DOM渲染在脚本执行前完成。-尽可能整合脚本,页面引入的脚本越少,加载响应越快。-减少内联javascript的使用。-所有的javascript标签都会按照引入的先后顺序依次执行,解析完上一个内容后才会解析下一个,所以注意多个javascript标签的引入顺序。-使用defer属性,它允许在文档完全呈现后执行脚本。-使用异步属性,当前脚本不必等待其他脚本的执行,也不需要阻塞文档的呈现。如有不妥欢迎指正!参考文章-英文参考文章-中文