zoukankan      html  css  js  c++  java
  • 游览器的解析与渲染

    游览器构成

    游览器内核

    • 游览器内核也称渲染引擎,主要有3种:
    • Trident内核: IE
    • Webkit内核:Chrome,Safari
    • Gecko内核:FireFox

    游览器工作

    1. DNS域名解析
    2. 建立TCP连接
    3. 发送HTTP请求
    4. 服务器处理请求
    5. 返回响应结果
    6. 关闭TCP连接
    7. 浏览器解析渲染

    游览器解析与渲染

    DNS域名解析

    我们在游览器输入网址后,游览器会首先会去查找本地hosts文件,检查在该文件中是否有相应的域名、IP对应关系,如果有,则向其IP地址发送请求,如果没有,再去找DNS服务器。

    在查询DNS服务器的过程中,客户端首先会向本地DNS服务器发送网址的查询报文,本地DNS服务器再把查询报文转发到根DNS服务器根DNS服务器再根据网址后缀派发指定的节点DNS服务器,然后本地DNS服务器再向这个节点DNS服务器发送查询请求,后者返回该网址对应的ip地址。

    本地DNS服务器的缓存中已有节点服务器的地址,则会直接向节点服务器发送查询请求,因此请求根域名服务器这一步不是必需的。

    从客户端到本地服务器属于递归查询,而DNS服务器之间的交互属于迭代查询

    建立TCP链接

    拿到服务器ip地址后,游览器客户端会开始与服务器进行交互,建立TCP链接,这个过程涉及三次握手,握手结束,则代表链接建立成功。

     

    发送HTTP请求

    与服务器建立了连接后,就可以向服务器发起请求了。请求报文结构如下:

    服务器处理请求

    服务器端收到请求后的由web服务器(准确说应该是http服务器)处理请求,诸如Apache、Ngnix、IIS等。web服务器解析用户请求,知道了需要调度哪些资源文件,再通过相应的这些资源文件处理用户请求和参数,并调用数据库信息,最后将结果通过web服务器返回给浏览器客户端。

     

    返回响应结果

    服务器处理完请求后,就会发送响应结果。响应报文的结构如下:

    响应结果中会有对应的HTTP状态码,可分为5类:

    关闭TCP连接

    为了避免服务器与客户端双方的资源占用和损耗,当双方没有请求或响应传递时,任意一方都可以发起关闭请求。与创建TCP连接的3次握手类似,关闭TCP连接,需要4次握手。

    游览器解析渲染

    关键渲染路径

    浏览器从最初接收请求来的HTML、CSS、javascript等资源,然后解析、构建树、渲染布局、绘制,最后呈现给客户能看到的界面这整个过程——简单来说,就是对游览器渲染过程的描述。

    渲染步骤

    1. 解析html,生成dom树
    2. 解析css,生成cssom树
    3. 将dom树和cssom树合并,生成渲染树
    4. 遍历渲染树,开始布局和计算
    5. 绘制渲染树,显示到屏幕

    渲染图示

    以webkit渲染引擎为例

    渲染过程

    解析html,生成dom树
    • 当浏览器接收到服务器响应来的HTML文档后,会自上而下扫描文档,开始解析,遍历文档节点,生成DOM树。
    • 整个构建过程其实包括: 字节 -> 字符 -> 令牌 -> 节点对象 -> 对象模型,下面是示例代码和配图:
    <html>
      <head>
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <link href="style.css" rel="stylesheet">
        <title>Critical Path</title>
      </head>
      <body>
        <p>Hello <span>web performance</span> students!</p>
        <div><img src="awesome-photo.jpg"></div>
      </body>
    </html>

     

    解析css,生成cssom树
    • 解析css文件,生成css规则树。
    • 每个css文件都被分析成一个stylesheet对象,每个对象都包含CSS规则。
    • css规则对象包含对应于css语法的选择器和声明对象以及其他对象。
    • 构建过程没有什么特别的差别,下面是示例代码和配图:
    body { font-size: 16px }
    p { font-weight: bold }
    span { color: red }
    p span { display: none }
    img { float: right }
    

      

    将dom树和cssom树合并,生成渲染树
    • 浏览器会先从dom树的根节点开始遍历每个可见节点,找到其适配的CSS样式规则并应用。
    • 将dom树与cssom树结合在一起,这就是渲染树。

    • 每一个渲染对象都对应着dom节点,但是非视觉(隐藏,不占位)dom元素不会插入渲染树,如<head>元素或声明display: none;的元素。
    • 渲染对象与dom节点不是简单的一对一的关系,一个dom可以对应一个渲染对象,但一个dom元素也可能对应多个渲染对象,因为有很多元素不止包含一个css盒子。(如当文本被折行时,会产生多个行盒,这些行会生成多个渲染对象;又如行内元素同时包含块元素和行内元素,则会创建一个匿名块级盒包含内部行内元素,此时一个dom对应多个渲染对象)
    遍历渲染树,开始布局和计算
    • 布局阶段会从渲染树的根节点开始遍历,然后确定每个节点对象在页面上的确切大小与位置。
    • 布局阶段的输出是一个盒子模型,它会精确地捕获每个元素在屏幕内的确切位置与大小,所有相对的测量值也都会被转换为屏幕内的绝对像素值。
    绘制渲染树,显示到屏幕
    • 在绘制阶段,浏览器会立即发出Paint Setup与Paint事件,开始将渲染树绘制成像素,绘制所需的时间跟CSS样式的复杂度成正比,绘制完成后,用户就可以看到页面的最终呈现效果了。

    相关知识补充

    资源并行加载

    • 现代浏览器总是并行加载资源,当html解析器被脚本阻塞时,解析器虽然会停止构建dom,但仍会识别该脚本后面的资源,并进行预加载

    重绘/重排/回流

    • 重绘(replaint)——屏幕的一部分重画,不影响整体布局,比如某个CSS的背景色变了,但元素的几何尺寸和位置不变。
    • 重排(relayout)——意味着元件的几何尺寸变了,我们需要重新验证并计算渲染树。
    • 回流(reflow)——Gecko中布局的称谓,同时也是重排的别称,是指渲染树的一部分或全部发生了变化。

    js阻塞dom解析

    • 由于js引擎和gui引擎互斥,所以当js执行的时候,gui就会被挂起,dom解析停滞,形成阻塞。
    • 值得注意的是,js只会阻塞后续的dom而不一定是整个dom,也就是说,在这个js前面的dom可以被正确地解析以及渲染(这也是为什么我们把脚本放在页面底部,脚本仍在下载时页面已经可以部分地正常显示)。

    css阻塞dom解析

    • 正常情况是不会的,但是当执行的js依赖于css的样式时就会发生,这种情况发生在css文件排在js文件之前
    • 当js执行时,考虑到文档解析,如果样式尚未加载或解析,将会得到错误信息。firefox和webkit浏览器处理策略不同,前者会阻塞所有脚本,后者只会阻塞操作了该文件内声明的样式属性的脚本。
    • 当游览器考虑到js执行需要css时,通过处理策略阻塞js脚本,dom解析自然也就被阻塞了,这也就是css为什么会阻塞dom解析

    css阻塞dom渲染

    • 默认情况下,css被视为阻塞dom渲染的资源,这意味着浏览器直至cssom构建完毕之前将不会渲染任何已处理的内容,毕竟渲染树也依赖于cssom树。
    • 这也是为什么我们把样式放在HTML内容之前,以防止被呈现内容发生样式跳动。 当然代价就是显示延迟,所以性能攸关的站点都会内联所有CSS

    动态插入js和css时

    • 动态插入的外部样式表或脚本不会阻塞dom解析或渲染。
    • 动态插入的内联样式表或脚本会阻塞dom解析和渲染。
    • 未加入到dom结构的样式表或脚本(外部或内联)不会被下载、解析或执行(Image.src是特例)。
    • 使用innerHTML引入script标签,其中的js不会执行,但link标签会起作用。

    改变js阻塞的方式

    • defer是渲染完再执行,async是下载完就执行(即不能保证执行顺序)。
    • defer相比普通script,有两点区别——载入js文件时不阻塞html的解析,执行阶段被放到html标签解析完成之后。
    • async加载的js依然会阻塞load事件。换句话说,async-script可能在 DOMContentLoaded 触发之前或之后执行,但一定在 load 触发之前执行。
    • 两者只在外链js中有效,并且使用document.createElement创建的script默认是async的。

    渲染图层

    描述

    • 浏览器渲染的图层一般包含两大类:普通图层以及复合图层。
    • 首先,普通文档流内可以理解为一个复合图层,这里称为默认复合层,里面不管添加多少元素,其实都是在同一个复合图层中。
    • 其次,absolute布局(fixed也一样),虽然可以脱离普通文档流,但它仍然属于默认复合层。
    • 然后,可以通过硬件加速的方式,声明一个新的复合图层,它会单独分配资源 (当然也会脱离普通文档流,这样一来,不管这个复合图层中怎么变化,也不会影响默认复合层里的回流重绘)。
    • 可以简单地理解为,GPU中各个复合图层是单独绘制的,所以互不影响,这也是为什么某些场景硬件加速效果一级棒。

    absolute和硬件加速的区别

    • 需要强调的是,absolute虽然可以脱离普通文档流,但是无法脱离默认复合层。 所以,就算absolute中信息改变时不会改变普通文档流中render树, 但是,浏览器最终绘制时,是整个复合层绘制的,所以absolute中信息的改变,仍然会影响整个复合层的绘制(浏览器会重绘它,如果复合层中内容多,absolute带来的绘制信息变化过大,资源消耗是非常严重的)。
    • 硬件加速直接就是在另一个复合层了,相当于另起炉灶,所以它的信息改变不会影响默认复合层 (当然了,内部肯定会影响属于自己的复合层),仅仅是引发最后的合成(输出视图)

    复合图层的作用

    • 一般一个元素开启硬件加速后会变成复合图层,可以独立于普通文档流中,改动后可以避免整个页面重绘,提升性能。但是尽量不要大量使用复合图层,否则由于资源消耗过度,页面反而会变的更卡

    如何变成复合图层(硬件加速)

    • 最常用的方式:translate3d、translateZ
    • opacity属性/过渡动画(需要动画执行的过程中才会创建合成层,动画没有开始或结束后元素还会回到之前的状态)
    • will-chang属性(这个比较偏僻),一般配合opacity与translate使用(而且经测试,除了上述可以引发硬件加速的属性外,其它属性并不会变成复合层), 作用是提前告诉浏览器要变化,这样浏览器会开始做一些优化工作(这个最好用完后就释放)
    • <video><iframe><canvas><webgl>等元素

    硬件加速时请使用index

    • 使用硬件加速时,尽可能的使用index,防止浏览器默认给后续的元素创建复合层渲染
    • 具体的原理时这样的: webkit CSS3中,如果这个元素添加了硬件加速,并且index层级比较低, 那么在这个元素的后面其它元素(层级比这个元素高的,或者相同的,并且releative或absolute属性相同的), 会默认变为复合层渲染,如果处理不当会极大的影响性能
    • 简单点理解,其实可以认为是一个隐式合成的概念:如果a是一个复合图层,而且b在a上面,那么b也会被隐式转为一个复合图层,这点需要特别注意

    优化手段

    针对html

    • html文档结构层次尽量少,最好不深于6层
    • 首屏html可以少量,主体结构动态插入

    针对css

    • 使用媒体查询,减少初次cssom树的构建量
    • 尽量用id和class,不要过渡层叠
    • 样式结构层次尽量简单

    针对js

    • 使用defer和async,避免对文档的阻塞
    • 可以的话,动态插入js,避免阻塞

    针对引入位置

    • css放到head,让cssom树先行构建;js放到</body>前,保证dom树先行构建,不被阻塞
    • 避免js文件的插入跟在css文件之后,避免css解析对js执行的延迟,造成阻塞

    针对资源载入

    • 对页面资源进行压缩,对传输进行gzip压缩
    • 利用link标签的rel属性进行预解析,运用http缓存

    参考资料

  • 相关阅读:
    Chandy-Lamport_algorithm
    3 differences between Savepoints and Checkpoints in Apache Flink
    列数 行数 表数 限制
    数据收集、传输、元数据管理、作业流调度、海量数据查询引擎、数据可视化
    分析云负载均衡产品
    端口被占用通过域名的处理 把www.domain.com均衡到本机不同的端口 反向代理 隐藏端口 Nginx做非80端口转发 搭建nginx反向代理用做内网域名转发 location 规则
    JSON Web Token
    查看开启端口的应用
    If the parts of an organization (e.g., teams, departments, or subdivisions) do not closely reflect the essential parts of the product, or if the relationship between organizations do not reflect the r
    微服务架构的理论基础
  • 原文地址:https://www.cnblogs.com/yongwunaci/p/10671999.html
Copyright © 2011-2022 走看看