浏览器渲染原理

前面的话

浏览器的工作原理你了解多少呢?在《奇舞周刊》上看到一篇关于浏览器渲染原理的文章,解析的很全面。小柒分两次梳理,这篇主要介绍浏览器组成即渲染过程。

浏览器组成

浏览器大体上由以下几个组件组成,各个浏览器可能有一点不同。

  • 界面控件 – 包括地址栏,前进后退,书签菜单等窗口上除了网页显示区域以外的部分
  • 浏览器引擎 – 查询与操作渲染引擎的接口
  • 渲染引擎 – 负责显示请求的内容。比如请求到HTML, 它会负责解析HTML、CSS并将结果显示到窗口中
  • 网络 – 用于网络请求, 如HTTP请求。它包括平台无关的接口和各平台独立的实现
  • UI后端 – 绘制基础元件,如组合框与窗口。它提供平台无关的接口,内部使用操作系统的相应实现
  • JS解释器 - 用于解析执行JavaScript代码
  • 数据存储持久层 - 浏览器需要把所有数据存到硬盘上,如cookies。新的HTML5规范规定了一个完整(虽然轻量级)的浏览器中的数据库 web database

[注意]:chrome浏览器与其他浏览器不同,chrome使用多个渲染引擎实例,每个Tab页一个,即每个Tab都是一个独立进程。

浏览器中的进程与线程

Chrome浏览器使用多个进程来隔离不同的网页。进程之间是不共享资源和地址空间的,不会存在太多的安全问题。但是多个线程之间共享着相同的地址空间和资源,所以线程之间会有恶意修改或非授权数据等复杂的安全问题。

浏览器内核

浏览器最重要或者说核心的部分是“Rendering Engine”,可大概译为“渲染引擎”,不过我们一般习惯将之称为“浏览器内核”。

在这里插入图片描述

负责对网页语法的解释(如标准通用标记语言下的一个应用HTML、JavaScript)并渲染(显示)网页。 所以,通常所谓的浏览器内核也就是浏览器所采用的渲染引擎,渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。

在内核控制下各线程相互配合以保持同步,一个浏览器通常由以下常驻线程组成:

1. GUI 渲染线程

  • 主要负责页面的渲染,解析HTML、CSS,构建DOM树,布局和绘制等。
  • 当界面需要重绘或者由于某种操作引发回流时,将执行该线程。
  • 该线程与JS引擎线程互斥,当执行JS引擎线程时,GUI渲染会被挂起,当任务队列空闲时,主线程才会去执行GUI渲染。。

2. JavaScript引擎线程

  • JS为处理页面中用户的交互,以及操作DOM树、CSS样式树来给用户呈现一份动态而丰富的交互体验和服务器逻辑的交互处理。

  • 该线程当然是主要负责处理 JavaScript脚本,执行代码。

  • 也是主要负责执行准备好待执行的事件,即定时器计数结束,或者异步请求成功并正确返回时,将依次进入任务队列,等待 JS引擎线程的执行。

  • GUI渲染线程与JS引擎线程互斥的,是由于JavaScript是可操纵DOM的,如果在修改这些元素属性同时渲染界面(即JavaScript线程和UI线程同时运行), 那么渲染线程前后获得的元素数据就可能不一致。两者不会同时进行。

3. 定时触发器线程

  • 负责执行异步定时器一类的函数的线程,如: setTimeout,setInterval。
  • 主线程依次执行代码时,遇到定时器,会将定时器交给该线程处理,当计数完毕后,事件触发线程会将计数完毕后的事件加入到任务队列的尾部,等待JS引擎线程执行。

4. 事件触发线程

  • 当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。

比如 setTimeout定时器计数结束, ajax等异步请求成功并触发回调函数,或者用户触发点击事件时,该线程会将整装待发的事件依次加入到任务队列的队尾,等待 JS引擎线程的执行。

5. 异步http请求线程

  • 负责执行异步请求一类的函数的线程,如: Promise,axios,ajax等。
  • 主线程依次执行代码时,遇到异步请求,会将函数交给该线程处理,当监听到状态码变更,如果有回调函数,事件触发线程会将回调函数加入到任务队列的尾部,等待JS引擎线程执行。
渲染过程
渲染流程

渲染流程有以下主要步骤:
在这里插入图片描述

  • 解析HTML生成DOM树 - 渲染引擎首先解析HTML文档,生成DOM树

  • 构建Render树 - 接下来不管是内联式,外联式还是嵌入式引入的CSS样式会被解析生成CSSOM树,根据DOM树与CSSOM树生成另外一棵用于渲染的树-渲染树(Render tree)

  • 布局(layout) - 根据渲染树对每个节点进行布局处理,确定其在屏幕上的显示位置。

  • 绘制(painting) - 根据渲染树以及回流得到的几何信息,得到节点的绝对像素

  • Display - 将像素发送给GPU,展示在页面上。

[注意]:为了提高用户体验,渲染引擎试图尽可能快的把结果显示给最终用户。它不会等到所有HTML都被解析完才创建并布局渲染树。它会在从网络层获取文档内容的同时把已经接收到的局部内容先展示出来。

渲染细节
  1. 生成DOM树

    DOM树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。

    DOM树的根节点就是document对象。

  2. 生成Render树

    生成DOM树的同时会生成样式结构体CSSOM(CSS Object Model)Tree,再 根据CSSOM和DOM树构造渲染树Render Tree。

    从MVC的角度来说,可以将Render树看成是V,DOM树与CSSOM树看成是M,C则是具体的调度者,比HTMLDocumentParser等。

  3. DOM树与Render树

    DOM对象类型很丰富,什么head、title、div,而Render树相对来说就比较单一了,毕竟它的职责就是为了以后的显示渲染用嘛。Render树的每一个节点我们叫它渲染器renderer。

在这里插入图片描述

从上图我们可以看出,renderer与DOM元素是相对应的,但并不是一一对 应,有些DOM元素没有对应的renderer,而有些DOM元素却对应了好几个 renderer,对应多个renderer的情况是普遍存在的,就是为了解决一个renderer描述不清楚如何显示出来的问题。

  1. 布局与绘制

    布局阶段:

    确定renderer的样式之后,然后就是显示元素布局。浏览器进行页面布局基本过程是以浏览器可见区域为画布,左上角为 (0,0)基础坐标,从左到右,从上到下从DOM的根节点开始画,首先确定显示元素的大小跟位置,此过程是通过浏览器计算出来的

    注意:用户CSS中定义的量未必就是浏览器实际采用的量。如果显示元素有子元素得先去确定子元素的显示信息。

    绘制(painting)阶段:

    渲染引擎会遍历Render树,并调用renderer的 paint() 方法,将renderer的内容显示在屏幕上。绘制工作是使用UI后端组件完成的。

  2. 回流与重绘

    回流(reflow): 当浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染。reflow 会从 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置。reflow 几乎是无法避免的。

    重绘(repaint): 改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变。

    每次Reflow,Repaint后浏览器还需要合并渲染层并输出到屏幕上。所有的这些都会是动画卡顿的原因。Reflow 的成本比 Repaint 的成本高得多的多。 一个结点的 Reflow 很有可能导致子结点,甚至父点以及同级结点的 Reflow 。在一些高性能的电脑上也许还没什么。 但是如果 Reflow 发生在手机上,那么这个过程是延慢加载和耗电的。

reflow与repaint的时机:
  • display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,因为没有发生位置变化。

  • 有些情况下,比如修改了元素的样式,浏览器并不会立刻 reflow 或 repaint 一次,而是会把这样的操作积攒一批,然后做一次 reflow,这又叫异步 reflow 或增量异步 reflow。

  • 有些情况下,比如 resize 窗口,改变了页面默认的字体等。对于这些操作,浏览器会马上进行 reflow。

补充知识

栅格化:

那为什么会有栅格化这个概念呢,在讲解这个概念之前我们先了解一下场景。开发者开发一个页面的时候可能图层会非常的大,需要滚动滚动条很久,如果渲染引擎把整个图层给全部绘制出来的话,其实没有必要,因为开销太大。所以合成线程会将图层划分为图块(title),然后合成线程会按照视口(viewport,指的是整个页面中用户看到的可视区域部分)附近的图块来优先生成位图,将图块生成位图的过程就是栅格化。在栅格化里,图块是其最小的单位。由于栅格化的时候计算量特别大,通常栅格化是渲染进程发送生成图块的指令给GPU,使用GPU加速,生成的位图保存于GPU内存中;如果没有GPU或者GPU资源占满,则渲染进程里则会维护一个栅格化的线程池用来生成位图。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值