当在浏览器输入URL回车后,浏览器到底做了什么?浏览器渲染机制又是怎样的?

594 阅读9分钟

当输入一个网址,浏览器到底做了什么?

当你输入一个URL也就是一个网址,浏览器到底发生了什么,这种问题既是老生常谈,对于新手来说也是面试考察重点,这是了解前端浏览器网通信机制的很重要的一步骤。在这里想用自己总结出来的一套文字来说明一下这个问题。

那么,我们输入网址后,实际发生了什么呢?过程如下:

一、输入一个网址
二、浏览器通过访问这个网址URL(也可以叫做域名(DN)之后有对域名DN和URL的区别解释,这里视为一样)利用域名系统(DNS)查找域名的IP地址。
在查询过程中事实上 ,浏览器会先去检索一些缓存地带,具体缓存地带如下:

  • 浏览器缓存 – 浏览器会缓存DNS记录一段时间。(2分钟到30分钟不等)。
  • 系统缓存 – 如果在浏览器缓存里没有找到需要的记录,浏览器会在操作系统中去检索DNS缓存记录。
  • 操作系统中HOST文件 – 如果在系统缓存里没找到,则继续检索系统的HOST文件去找到有没有DNS缓存记录。
  • 如果在操作系统中也没有发现缓存DNS记录,则操作系统将这个域名发送至LDNS(本地域名服务器系统,如果你是电信网,LDNS就在电信那里)LDNS查询自己的缓存(可以说一般绝对大多数情况都能在这里查到),如果查询成功则返回结果,如果查询失败则发起一次迭代DNS解析请求。
    如果最终的是在LDNS里找到记录的话,则会实现以下步骤:
    1. LDNS向Root Name Server发起请求,此处,Root Name Server返回com域的顶级域名服务器地址。
    2. LDNS向com域的顶级域名服务器发起请求,返回baidu.com域名服务器地址;
    3. LDNS向baidu.com域名服务器发起请求,得到www.baidu.com的IP地址。
    4. LDNS将得到的IP地址返回给操作系统,同时操作系统自己也将把这个IP地址保存起来,方便以后使用。
    5. 操作系统将IP地址返回给浏览器,同时浏览器自己也将把这个IP地址保存起来,方便以后使用。
    6. 至此,浏览器已得到域名对应的IP地址了。
      补充说明:
  • 域名(DN)和URL是有区别的。域名是一台或一组服务器的名称,用来确定服务器的位置;URL是统一资源定位符,用来确认某一文件的具体位置。例如:bilibili.com是哔哩哔哩的域名(DN),但bilibili.com/video/av15690032/ 是URL,可以见得URL其实是域名(DN)的服务器里一个具体文件的地址。
  • IP地址和域名(DN)也不是一一对应的。可以把多个提供相同服务的服务器IP设置成为同一个域名(DN)下。但同一时刻,一个域名(DN)只能解析出一个IP地址。也就是说,我们在输入一个域名bilibili.com时,有可能其背后有多个IP地址,具体分配到哪一个IP地址论情况而定,但最终肯定只会分配到某一个IP地址里去。

    建立连接 三次握手

    知道服务器IP地址后,下面就开始客户端浏览器和服务器建立连接了:
    1.主机向服务器发送一个建立链接的请求(你好,约吗!)
    2.服务器接受到请求后发送同意连接的信号(你好,约!)
    3.主机接收到同意信号后,再次向服务器发送确认信号(很高兴能约到你!)。自此,主机与服务器建立了连接。
    注:三次握手采用TCP协议,起可以保证信息传输的可靠性,三次握手中,如果有一方没接收到确认信号,协议会要求重新发送信号。

三、建立连接成功后,浏览器就给服务器发送一个HTTP请求
四、网站服务的永久重定向响应。
解释:服务器给浏览器响应一个301永久重定向响应,为什么服务器一定要重定向而不是直接发会用户想看的网页内容呢?其中一个原因跟搜索引擎排名有关。如果一个页面有两个地址,就像www.bilibili.com/bilibili.com/ 搜索引擎会认为它们是两个网站,结果造成每一个的搜索链接都减少从而降低排名。而搜索引擎知道301永久重定向是什么意思,这样就会把访问带www的和不带www的地址归到同一个网站排名下。还有一个是用不同的地址会造成缓存友好性变差。当一个页面有好几个名字时,它可能会在缓存里出现好几次。
五、浏览器跟踪重定向响应地址。
六、服务器处理请求
七、浏览器返回需要请求的HTML文件
八、浏览器开始加载HTML文件,渲染并显示在浏览器上。
九、在加载HTML文件中,一定在HTML文件中有其他需要加载的图片或者JS、css文件等等,然后浏览器继续发出请求,并加载他们,嵌入到HTML文件中去。

浏览器渲染机制又是怎样的?

在我们输入一个URL点击回车,浏览器大致就做了这些事情。在上面的第八的一个步骤,提及到渲染年并显示到浏览器上,那么这样的渲染过程又是怎样实现的呢?
浏览器渲染的基本流程如下:
解析HTML文件构建DOM树->构建render树->布局render树->绘制render树

  1. 首先浏览器会将HTML文件解析成DOM树,DOM树的构建过程是一个深度遍历的过程,也就是说当所有子节点布置好了后才会去布置这个子节点的兄弟节点。
  2. 然后将CSS构建成CSS规则树。
  3. 根据DOM树和CSS规则树来构建Render树(在Render树中不会出现header标签或display:none的标签)。生成Render树时浏览器是不知道各个节点子浏览器中的具体位置的。
  4. 然后进入布局(layout)render树。布局并确定每个节点在浏览器中的真正位置,宽,高,颜色等。
  5. 最后一步就是绘制render树,浏览器将布局好的render树绘制画出来。

    上面的过程是一步一步完成的。但是,浏览器会了提高效率,并不是等所有的HTML文件解析成DOM树再进行渲染和布局的,而是先解析完一部分,就紧接着渲染,再解析余下的部分。

    关于渲染机制的两个概念:
    reflow(重排、回流):在浏览器进行第4项layout布局render树过程时,其实浏览器就在做reflow的操作。布局是要花时间的,当浏览器发现某个部分的变化影响了布局(改变宽,高,删除,添加节点,移动节点布局位置,修改浏览器默认字体,resize浏览器窗口),需要倒回去重新布局,这个过程叫reflow。
    repaint(重绘):在浏览器进行第5项绘制render树时其实就是进行的repaint操作,在浏览器布局render树完成之后,布局不会再发生改变,仅仅发生一些绘制上的改变(例如改变背景颜色或字体颜色),则需要重新绘制画画。
    所以:回流必将引起重绘,而重绘不一定会引起回流。
    reflow和repaint都是无法避免的。我们只能够尽可能少地去避免过多的reflow和repaint。
    避免reflow和repaint的方法:

    1. 绝对定位,position:absolute或position:fixed。这样,元素就脱离了文档流,它的变化不会影响到其他元素布局。不过绝对布局丧失了许多灵活性。
    2. 在JS里不要一条一条去修改CSS样式的属性的值,应该预先写好需要的css的各个样式属性的值,做一个命名,然后只需要修改 DOM 的 className的命名就可以了。
      // 不好的写法
      var left = 10,
      top = 10;
      el.style.left = left + "px";
      el.style.top  = top  + "px";
      el.style.background = '#eee'; 
      // 比较好的写法
      el.className += " theclassname";
    3. 不要用tables布局。
    4. 避免使用CSS的JS表达式
    5. 不要把DOM节点的属性值拿到循环体里面去做循环,最好是先保存好这个属性值,再去做循环。

HTML页面加载和解析流程

  1. 用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件;
  2. 浏览器开始载入html代码,发现<head>标签内有一个<link>标签引用外部CSS文件;
  3. 浏览器又发出CSS文件的请求,服务器返回这个CSS文件;
  4. 浏览器继续载入html中<body>部分的代码,并且CSS文件已经拿到手了,可以开始渲染页面了;
  5. 浏览器在代码中发现一个<img>标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;
  6. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码;
  7. 浏览器发现了一个包含一行Javascript代码的<script>标签,赶快运行它;
  8. Javascript脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个<div> (style.display=”none”)。突然少了这么一个元素,浏览器不得不重新渲染这部分代码;
  9. 终于等到了</html>的到来,浏览器泪流满面……
  10. 等等,还没完,用户点了一下界面中的“换肤”按钮,Javascript让浏览器换了一下<link>标签的CSS路径;
  11. 浏览器召集了在座的各位<div><span><ul><li>们,“大伙儿收拾收拾行李,咱得重新来过……”,浏览器向服务器请求了新的CSS文件,重新渲染页面。