浏览器渲染页面过程剖析(当用户在地址栏输入URL点击回车后。。。)

整体过程

  1. 用户输入URL地址

  2. 对URL地址进行DNS域名解析

  3. 建立TCP连接(三次握手)

  4. 浏览器发送HTTP请求报文

  5. 服务器返回HTTP响应报文

  6. 关闭TCP连接(四次挥手)

  7. 浏览器解析文档资源并渲染页面

DNS域名解析

为什么需要DNS解析域名为IP地址?

网络通讯大部分是基于TCP/IP的,而TCP/IP是基于IP地址的,所以计算机在网络上进行通讯时只能识别如“202.96.134.133”之类的IP地址,而不能认识域名。我们无法记住10个以上IP地址的网站,所以我们访问网站时,更多的是在浏览器地址栏中输入域名,就能看到所需要的页面,这是因为有一个叫“DNS服务器”的计算机自动把我们的域名“翻译”成了相应的IP地址,然后调出IP地址所对应的网页。

DNS了解一下

DNS( Domain Name System)是“域名系统”的英文缩写,是一种组织成域层次结构的计算机和网络服务命名系统,它用于TCP/IP网络,它所提供的服务是用来将主机名和域名转换为IP地址的工作。

DNS解析过程

浏览器收到URL后,先去本地host文件中查找是否有对应的域名IP关系,如果有即向IP地址发起请求;如果没有,将到DNS服务器中查找。

DNS分为本地DNS服务器,根DNS服务器和各个子DNS服务器。

浏览器渲染页面过程剖析(当用户在地址栏输入URL点击回车后。。。)_第1张图片
浏览器渲染页面过程剖析(当用户在地址栏输入URL点击回车后。。。)_第2张图片

从浏览器到本地DNS服务器属于递归查询,而DNS服务器之间属于迭代查询。

建立TCP连接

通俗理解

TCP连接就是我们常谈的三次握手过程

客户端:“你好在吗?我要给你发送东西咯~!”

服务端:“嗯嗯我在啊!你发吧~”

客户端: “嗯啊-8-”

图解

浏览器渲染页面过程剖析(当用户在地址栏输入URL点击回车后。。。)_第3张图片
  1. 客户端发送连接请求报文段,将SYN位置为1,Seq为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;
  2. 服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置ACK为x+1;同时,自己自己还要发送SYN请求信息,将SYN位置为1,Seq为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
  3. 客户端收到服务器的SYN+ACK报文段。然后将ACK设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

为什么是三次握手而不是两次,四次呢?

在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。在另一部经典的《计算机网络》一书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。

在谢希仁著《计算机网络》书中同时举了一个例子,如下:

“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

在知乎上有个生动的比喻:

三次握手:
“喂,你听得到吗?”
“我听得到呀,你听得到我吗?”
“我能听到你,今天balabala……”

两次握手:
“喂,你听得到吗?”
“我听得到呀”
“喂喂,你听得到吗?”
“草,我听得到呀!!!!”
“你TM能不能听到我讲话啊!!喂!”
“……”

四次握手:
“喂,你听得到吗?”
“我听得到呀,你听得到我吗?”
“我能听到你,你能听到我吗?”
“……不想跟傻逼说话”

浏览器发送HTTP请求报文

(略)

服务器返回HTTP响应报文

(略)

关闭TCP连接

通俗理解

TCP连接关闭时进行四次握手过程

客户端:“你好,我这边没有数据要传了,我要关闭咯。”

服务端:“收到~我看一下我这边有没数据要传的。”

服务端:“我这边也没有数据要传啦,我们可以关闭连接咯~”

客户端:”ojbk~“

图解

浏览器渲染页面过程剖析(当用户在地址栏输入URL点击回车后。。。)_第4张图片
  1. 主机1(可以使客户端,也可以是服务器端),设置Seq和Ack,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
  2. 主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Ack为Seq加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求;
  3. 主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;
  4. 主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。

浏览器解析文档资源并渲染页面

  1. HTML解析出DOM Tree

  2. CSS解析出CSSOM Tree

  3. JavaScript代码由JavaScript引擎处理

  4. DOM树建立后根据CSS样式进行构建内部绘图模型,生成RenderObject树

  5. 根据网页层次结构构建RenderLayer树,同时构建虚拟绘图上下文

  6. 依赖2D和3D图形库渲染成图像结果呈现在浏览器中(Painting)

我们以webkit内核浏览器渲染过程为例

浏览器渲染页面过程剖析(当用户在地址栏输入URL点击回车后。。。)_第5张图片

HTML解析

HTML Parser的任务是将HTML标记解析成DOM Tree

浏览器渲染页面过程剖析(当用户在地址栏输入URL点击回车后。。。)_第6张图片

CSS解析

CSS Parser将CSS解析成Style Rules,Style Rules也叫CSSOM(CSS Object Model)。
StyleRules也是一个树形结构,根据CSS文件整理出来的类似DOM Tree的树形结构

浏览器渲染页面过程剖析(当用户在地址栏输入URL点击回车后。。。)_第7张图片

JavaScript处理

浏览器解析文档,当遇到script标签的时候,会立即解析脚本,停止解析文档(因为JS可能会改动DOM和CSS,所以继续解析会造成浪费)。
如果脚本是外部的,会等待脚本下载完毕,再继续解析文档。现在可以在script标签上增加属性 defer或者async。
脚本解析会将脚本中改变DOM和CSS的地方分别解析出来,追加到DOM Tree和Style Rules上。

布局(回流)

创建渲染树后,下一步就是布局(Layout),或者叫回流(reflow,relayout),这个过程就是通过渲染树中渲染对象的信息,计算出每一个渲染对象的位置和尺寸,将其安置在浏览器窗口的正确位置,而有些时候我们会在文档布局完成后对DOM进行修改,这时候可能需要重新进行布局,也可称其为回流,本质上还是一个布局的过程,每一个渲染对象都有一个布局或者回流方法,实现其布局或回流。

绘制(重绘)

在绘制阶段,系统会遍历呈现树,并调用呈现器的“paint”方法,将呈现器的内容显示在屏幕上。绘制工作是使用用户界面基础组件完成的。
CSS2 规范定义了绘制流程的顺序。绘制的顺序其实就是元素进入堆栈样式上下文的顺序。这些堆栈会从后往前绘制,因此这样的顺序会影响绘制。块呈现器的堆栈顺序如下:

  1. 背景颜色
  2. 背景图片
  3. 边框
  4. 子代
  5. 轮廓

Reflow的成本比Repaint的成本高得多的多。DOM Tree里的每个结点都会有reflow方法,一个结点的reflow很有可能导致子结点,甚至父点以及同级结点的reflow。在一些高性能的电脑上也许还没什么,但是如果reflow发生在手机上,那么这个过程是非常痛苦和耗电的。 所以,下面这些动作有很大可能会是成本比较高的。

  • 当你增加、删除、修改DOM结点时,会导致Reflow或Repaint

  • 当你移动DOM的位置,或是搞个动画的时候。

  • 当你修改CSS样式的时候。

  • 当你Resize窗口的时候(移动端没有这个问题),或是滚动的时候。

  • 当你修改网页的默认字体时。

  • 注:display:none会触发reflow,而visibility:hidden只会触发repaint,因为没有发现位置变化。

基本上来说,reflow有如下的几个原因:

  • Initial。网页初始化的时候。

  • Incremental。一些Javascript在操作DOM Tree时。

  • Resize。其些元件的尺寸变了。

  • StyleChange。如果CSS的属性发生变化了。

  • Dirty。几个Incremental的reflow发生在同一个frame的子树上。

参考文章

DNS原理及其解析过程

通俗大白话来理解TCP协议的三次握手和四次分手

TCP的三次握手四次挥手

浏览器渲染页面过程与页面优化

细说浏览器输入URL后发生了什么

(完)

你可能感兴趣的:(浏览器渲染页面过程剖析(当用户在地址栏输入URL点击回车后。。。))