浏览器从URL输入到页面展现到底发生了什么? 回流、重绘


1、浏览器上输入url

  • 用户输入url,例如http://www.baidu.com。
  • 其中http为协议,www.baidu.com为网络地址,及指出需要的资源在那台计算机上。
  • 一般网络地址可以为域名或IP地址,此处为域名。
  • 使用域名是为了方便记忆,但是为了让计算机理解这个地址还需要把它解析为IP地址。

2、应用层DNS解析域名

什么是DNS?

  • DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。
  • 通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。

通俗的讲,我们更习惯于记住一个网站的名字,比如www.baidu.com,而不是记住它的ip地址,比如:167.23.10.2。而计算机更擅长记住网站的ip地址,而不是像www.baidu.com等链接。因为,DNS就相当于一个电话本,比如你要找www.baidu.com这个域名,那我翻一翻我的电话本,我就知道,哦,它的电话(ip)是167.23.10.2。

DNS解析过程:

  1. 浏览器先检查自身缓存中有没有被解析过的这个域名对应的 IP 地址。
  2. 浏览器缓存中没有命中,浏览器会检查操作系统缓存中有没有对应的已解析过的结果。(在 Windows 中可通过 C 盘里一个叫 hosts 的文件来设置,如果你在这里指定了一个域名对应的 IP 地址,那浏览器会首先使用这个 IP 地址。)
  3. 至此还没有命中域名,会请求本地域名服务器(LDNS)来解析这个域名,这台服务器一般在你的城市的某个角落,距离你不会很远,并且这台服务器的性能都很好,一般都会缓存域名解析结果,大约 80% 的域名解析到这里就会完成。
  4. LDNS 仍然没有命中,就直接跳到 Root Server 域名服务器请求解析。
  5. 根域名服务器返回给 LDNS 一个所查询域的主域名服务器(gTLD Server,国际顶尖域名服务器,如.com .cn .org 等)地址。
  6. 此时 LDNS 再发送请求给上一步返回的 gTLD Server。
  7. 接受请求的 gTLD Server 查找并返回这个域名对应的 Name Server 的地址,这个 Name Server 就是网站注册的域名服务器。
  8. Name Server 根据映射关系表找到目标 IP,返回给 LDNS。LDNS 缓存这个域名和对应的 IP。
  9. LDNS 把解析的结果返回给用户,用户根据 TTL 值缓存到本地系统缓存中,域名解析过程至此结束。

3、应用层客户端发送HTTP请求

互联网内各网络设备间的通信都遵循TCP/IP协议,利用TCP/IP协议族进行网络通信时,会通过分层顺序与对方进行通信。

分层由高到低分别为:应用层、传输层、网络层、数据链路层。发送端从应用层往下走,接收端从数据链路层网上走。

在这里插入图片描述

得到 IP 地址后,浏览器会开始构造一个 HTTP 请求,应用层客户端向服务器端发送的HTTP请求包括:请求行请求头请求正文

请求消息格式:

请求行(方法 空格/URL 空格 协议/版本号)
消息报头 可选
空行 发送回车符和换行符,通知服务器以下不再有请求头。
消息正文 可选

在这里插入图片描述
在这里插入图片描述

请求行

  • 包括:请求方法开头,以空格分开,后面跟着请求的URI和协议的版本。

eg:
GET /index.html HTTP/1.1
POST /index.html HTTP/1.1
Delete /index.html HTTP/1.1

请求的方法

  • GET 请求获取URI所标识的资源
  • POST 请求URI所标识的资源,并请求服务器接收附加在请求后面的数据,常用于表单提交。
  • HEAD 请求获取由URI所标识的资源的响应消息报头
  • PUT 请求服务器存储一个资源,并用URI作为其标识
  • DELETE 请求服务器删除URI所标识的资源
  • TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
  • CONNECT 保留将来使用
  • OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求

请求头

  • 请求头包含请求的附加信息,由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。

常见的请求头如下:

  • Accept:指定浏览器或其他客户程序能够处理的MIME类型:request.getHeader(“Accept”);
  • Accept-Charse: 使用的字符集,如ISO-8859-1
  • Accept-Encoding:客户端能够处理的编码类型,如gzip或compress
  • Accept-Language:客户端的首选语言
  • Authorization:客户用这个报头来标识自己的身份
  • Connnection:标明客户是否能够处理持续性HTTP连接。持续性连接允许客户或者浏览器在单个socket中读取多个文件,从而节省协商几个独立连接所需的开销
  • Content-Length:只适用于POST请求,用来给定POST数据的大小,以字节为单位:request.getContentLength
  • Cookie:向服务器返回cookie,这些cookie是之前由服务器发送给浏览器的:request.getCookies
  • Host:标明原始URL中给出的主机名和端口号
  • If-Modified-Since:仅当页面在指定日期之后发生改变的情况下,客户程序才希望获取该页面。如果没有更新的结果,则服务器发送304报头。这个选项十分有用,因为使用它,浏览器可以缓存文档,只在它们发生改变时才通过网络重新载入它们
  • Referer:标明引用Web页面的URL
  • User-Agent:求的浏览器或者其他客户程序

Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2  
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://localhost/

请求正文

  • 可以承载多个请求参数的数据,包含回车符、换行符和请求数据,并不是所有请求都具有请求数据

username=detanx&password=Aa123456  // 请求数据

HTTP 请求是纯文本格式的,所以在 TCP 的数据段中可以直接分析 HTTP 文本的。

4、传输层TCP传输报文

  • 位于传输层的TCP协议为传输报文提供可靠的字节流服务。
  • 它为了方便传输,将大块的数据分割成以报文段为单位的数据包进行管理,并为它们编号,方便服务器接收时能准确地还原报文信息。
  • TCP协议通过"三次握手"等方法保证传输的安全可靠。

南栀的博客—三次握手

5、网络层IP协议查询MAC地址

  • IP协议的作用是把TCP分割好的各种数据包传送给接收方。
  • 要保证确实能传到接收方还需要接收方的MAC地址,也就是物理地址。
  • IP地址和MAC地址是一一对应的关系,一个网络设备的IP地址可以更换,但是MAC地址一般是固定不变的。
  • ARP协议可以将IP地址解析成对应的MAC地址。当通信的双方不在同一个局域网时,需要多次中转才能到达最终的目标,在中转的过程中需要通过下一个中转站的MAC地址来搜索下一个中转目标。

6、数据到达数据链路层

在找到对方的MAC地址后,就将数据发送到数据链路层传输。这时,客户端发送请求的阶段结束。

7、服务器接收数据

  • 接收端的服务器在链路层接收到数据包,再层层向上直到应用层。
  • 这过程中包括在运输层通过TCP协议将分段的数据包重新组成原来的HTTP请求报文。

8、服务器响应请求,并返回http报文

服务接收到客户端发送的HTTP请求后,查找客户端请求的资源,并返回响应报文。

HTTP响应三部分:状态行响应头响应正文
在这里插入图片描述

状态行

  • 状态行由 3 部分组成,分别为:协议版本状态码状态码描述
  • 各元素之间以空格分隔。
  • 其中协议版本与请求报文一致,状态码描述是对状态的简单描述。

HTTP/1.1 200 OK // 状态行

常见状态码:

  • 200 OK:客户端请求成功
  • 302 Move temporarily:请求的资源现在临时从不同的 URI 响应请求。
  • 400 Bad Request :客户端请求有语法错误,不能被服务器所理解
  • 401 Unauthorized: 请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
  • 403 Forbidden :服务器收到请求,但是拒绝提供服务
  • 404 Not Found:请求资源不存在,eg:输入了错误的URL
  • 500 Internal Server Error: 服务器发生不可预期的错误
  • 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常

响应头
响应头与请求头一样,只是与请求头包含的附加信息有所不同。

常见响应报头

  • Allow: 指定服务器支持的请求方法(GET,POST等)
  • Cache-Control: 告诉浏览器或者其他客户,什么环境可以安全地缓存文档
  • Connection: close值,指定浏览器不用使用持续性的HTTP连接
  • Content-Disposition: 要求浏览器询问客户,将响应存储在磁盘上给定名称的文件中
  • Content-Encoding: 标明页面在传输过程中所使用的编码方式
  • Content-Language: 文档使用的语言
  • Content-Length: 响应中的字节
  • Content-Type: MIME
  • Expires: 规定内容的过期时间,从而不再需要继续缓存:response.setDataHeader(“Expires”, Time)
  • Last-Modified: 标明文件最后的修改时间
  • Location: 300-399之间的所有响应都应该包括这个报头,它通知浏览器文档的地址
  • Refresh: 标明浏览器应该多长时间之后请求最新的页面:response.setIntHeader(“Refresh”, 30)
  • Set-Cookie: 指定一个同页面相关的cookie

// 响应头
Date: Sun, 17 Mar 2013 08:12:54 GMT  
Set-Cookie: PHPSESSID=c0huq7pdkmm5gg6osoe3mgjmm3; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 4393
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json

相应数据

  • 根据请求类型的不同,响应的数据格式也有所不同,有可能是二进制文件流、JSON 对象、字符串、HTML 文件等。

请求头和响应头是浏览器和服务器之间交互的重要信息,由程序自动处理,通常不需要人为干预。

9、浏览器解析渲染页面

在这里插入图片描述

浏览器使用流式布局模型 (Flow Based Layout)。

  • css的加载和解析不会阻塞html文档的解析
  • css的解析会阻塞js的执行,必须等到CSSOM生成后才能执行js
  • js的执行会阻塞html文档的解析
  • html一边解析一边显示
  • css必须完全解析完毕才能进入生成渲染树环节

浏览器渲染过程

  1. 浏览器把获取到的html代码解析成1个Dom树,html中的每个tag都是Dom树中的1个节点,根节点就是我们常用的document对象 。dom树里面包含了所有的html tag,包括display:none隐藏,还有用JS动态添加的元素等。
  2. 浏览器把所有样式(主要包括css和浏览器的样式设置)解析成样式结构体(cssom),在解析的过程中会去掉浏览器不能识别的样式,比如IE会去掉-moz开头的样式.
  3. dom tree和样式结构体(cssom)结合后构建呈现树(render tree),render tree有点类似于dom tree,但其实区别有很大,render tree能识别样式,render tree中每个node都有自己的style,而且render tree不包含隐藏的节点(比如display:none的节点,还有head节点),因为这些节点不会用于呈现,而且不会影响呈现的,所以就不会包含到 render tree中。visibility:hidden隐藏的元素还是会包含到render tree中的,因visibility:hidden 会影响布局(layout),会占有空间。
  4. Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
  5. Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素。
  6. Display:将像素发送给GPU,展示在页面上。

有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。

由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。

回流必将引起重绘,重绘不一定会引起回流。

回流(reflow)

当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

一个元素的回流可能会导致了其所有子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流。

导致回流的操作:

  • 页面首次渲染
  • 浏览器窗口大小发生改变
  • 元素尺寸或位置发生改变
  • 元素内容变化(文字数量或图片大小等等)
  • 元素字体大小变化
  • 添加或者删除可见的DOM元素
  • 激活CSS伪类(例如::hover)
  • 查询某些属性或调用某些方法

一些常用且会导致回流的属性和方法:

  • clientWidth、clientHeight、clientTop、clientLeft
  • offsetWidth、offsetHeight、offsetTop、offsetLeft
  • scrollWidth、scrollHeight、scrollTop、scrollLeft
  • scrollIntoView()、scrollIntoViewIfNeeded()
  • getComputedStyle()
  • getBoundingClientRect()
  • scrollTo()

重绘(repain)

当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

var s = document.body.style; 

s.padding = "2px"; // 回流+重绘

s.border = "1px solid red"; // 再一次 回流+重绘

s.color = "blue"; // 再一次重绘

s.backgroundColor = "#ccc"; // 再一次 重绘

s.fontSize = "14px"; // 再一次 回流+重绘

// 添加node,再一次 回流+重绘
document.body.appendChild(document.createTextNode('abc!'));

///可以看到每次DOM元素的样式操作都会引发重绘,如果涉及布局还会引发回流。

回流、重绘性能影响分析

回流比重绘的代价要更高。

有时即使仅仅回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流。

现代浏览器会对频繁的回流或重绘操作进行优化:

  • 浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。

当你访问以下属性或方法时,浏览器会立刻清空队列:

  • clientWidth、clientHeight、clientTop、clientLeft
  • offsetWidth、offsetHeight、offsetTop、offsetLeft
  • scrollWidth、scrollHeight、scrollTop、scrollLeft
  • width、height
  • getComputedStyle()
  • getBoundingClientRect()

避免回流、重绘

CSS

  • 使用 transform 替代 top
  • 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)
  • 避免使用table布局,可能很小的一个小改动会造成整个 table 的重新布局。
  • 尽可能在DOM树的最末端改变class,回流是不可避免的,但可以减少其影响。尽可能在DOM树的最末端改变class,可以限制了回流的范围,使其影响尽可能少的节点。
  • 避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。
  • 将动画效果应用到position属性为absolute或fixed的元素上,避免影响其他元素的布局,这样只是一个重绘,而不是回流,同时,控制动画速度可以选择 requestAnimationFrame
  • 避免使用CSS表达式,可能会引发回流。
  • 将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点,例如will-change、video、iframe等标签,浏览器会自动将该节点变为图层。
  • CSS3 硬件加速(GPU加速),使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘 。但是对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。

JavaScript

  • 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
  • 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
  • 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
  • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
  • 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

10、 tcp四次挥手断开连接

南栀的博客—四次挥手

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南栀~zmt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值