关于前端:图解浏览器的多进程渲染机制

2次阅读

共计 4900 个字符,预计需要花费 13 分钟才能阅读完成。

引言

察看浏览器的工作管理器能够发现,关上浏览器的一个页面须要多个过程,包含浏览器过程、GPU 过程、网络过程、渲染过程等,有插件的话还会包含各种插件过程(Chrome 选项 -> 更多工具 -> 工作管理器)。

本文将聚焦于浏览器的各个过程间是如何配合,将页面出现给用户的。

📌 你将理解到

  • 浏览器在历史倒退过程中,其过程架构做了哪些调整,为什么这样调整,以及解决了哪些问题?
  • 从用户在地址栏输出 URL,到页面渲染实现这之间产生了什么?回流和重绘是如何对浏览器性能造成影响的?

1. 浏览器过程架构的演变

过程和线程

过程

  • 一个过程就是一个程序的运行实例,它是由用来寄存代码、运行中的数据以及一个执行工作的主线程的内存组成的运行环境;
  • 当一个过程敞开后,操作系统会回收为该过程调配的内存(即便该过程中存在因操作不当导致内存透露的线程);
  • 过程之间的内容是互相隔离的,这是为了爱护操作系统中的过程互不烦扰;
  • 当过程之间须要进行通信时,可应用过程间通信(IPC)机制。

线程

  • 线程是由过程来启动和治理的,一个应用程序在执行的时候会存在多个子工作的状况,应用多线程并行处理能够大大晋升性能;
  • 因为线程依附于过程,过程中的任一线程执行出错也会导致整个过程的解体(因为内存是共享的);
  • 同一过程中的多个线程可共享过程所领有的资源。这种资源包含内存空间,也包含操作系统的权限。
单过程和多过程浏览器

单过程浏览器

单过程浏览器是指所有功能模块(网络、插件、JS 运行环境、渲染引擎、页面等)都运行在同一过程中的浏览器(晚期的 IE、Firefox)。

单过程浏览器存在的问题:

  • 【不稳固】
    • 浏览器中的插件运行在浏览器的过程之中,插件的解体会引起整个浏览器的解体;
    • 渲染引擎通常也是不稳固的,例如简单的 JS 脚本也会引起渲染引擎的解体,最终导致浏览器解体。
  • 【不晦涩】
    • CPU 在某个工夫点只能执行某个过程中的某一条线程。因为单过程浏览器中所有的页面的各种模块都在同一线程中运行,即同一时刻只能有一个模块能够执行。
    • 当一个页面的某个模块阻塞了该线程,就会导致整个浏览器失去响应;此外,页面的内存透露也会导致单过程浏览器应用工夫越长,反馈越慢。
  • 【不平安】
    • 线程共享过程资源,因此插件就能获取到浏览器运行过程中的数据,以及领有和浏览器等同的零碎权限。
    • 例如,插件可应用 C/C++ 编写,通过插件能够获取到操作系统任意资源;脚本也能够通过浏览器的破绽来获取零碎权限,引发平安问题。
多过程浏览器

Chrome 一问世便应用了多过程的架构,其页面运行在了独自的渲染过程中,插件运行在独自的插件进行中,过程间应用 IPC 进行通信。

浏览器的次要过程有哪些:

  • 浏览器过程。相当于浏览器的大脑,次要负责界面显示、用户交互、子过程治理,同时提供存储等性能。
  • 渲染过程。外围工作是将 HTML、CSS 和 JavaScript 转换为用户能够与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该过程中。

默认状况下,Chrome 会为每个 Tab 标签创立一个渲染过程。因为渲染过程所有的内容都是通过网络获取的,会存在一些恶意代码利用浏览器破绽对系统进行攻打,所以运行在渲染过程外面的代码是不被信赖的。这也是为什么 Chrome 会让渲染过程运行在平安沙箱里,就是为了保证系统的平安。

  • 网络过程。次要负责页面的网络资源加载,之前是作为一个模块运行在浏览器过程外面的,目前已独立进去,成为一个独自的过程。
  • 插件过程。次要是负责插件的运行,因插件易解体,所以须要通过插件过程来隔离,以保障插件过程解体不会对浏览器和页面造成影响。
  • GPU 过程。当页面应用了硬件加速时,会应用它来渲染页面。

其实,Chrome 刚开始公布的时候是没有独自 GPU 过程的,都是放到浏览器主过程中的。而 GPU 的应用初衷是为了实现 3D CSS 的成果,只是随后网页、Chrome 的 UI 界面都抉择采纳 GPU 来绘制,这使得 GPU 成为浏览器广泛的需要。最初,Chrome 在其多过程架构上也引入了 GPU 过程。

多过程浏览器是如何解决单过程浏览的问题的:

  • 【不稳固】正是因为过程之间互相隔离,当一个页面或者插件解体时只会影响以后的过程,不会影响到浏览器和其余页面。
  • 【不晦涩】因为 JS 脚本运行在渲染过程中,即便 JS 阻塞了渲染过程,也只会影响以后页面的渲染,而其余页面的脚本则会运行在他们本人的渲染过程中,不受影响;此外,内存透露导致的不晦涩问题也会随着一个页面的敞开导致一个过程的完结而解决。
  • 【不平安】多过程架构的平安沙箱,相当于是操作系统给过程上了一把锁,沙箱中的程序可运行不可写入、不可读取敏感数据。

多过程浏览器存在的问题:

  • 更高的资源占用。以 Chrome 浏览器为例,其将为每个页面调配独自的渲染过程,为每个插件调配独自的插件过程,因而会耗费更多内存资源。
  • 更简单的体系架构。浏览器各个模块之间耦合度高、扩展性差目前的架构较难适应新需。

2. 导航流程

从用户收回 URL 申请到页面开始解析的过程,叫做导航,是网络加载流程和渲染流程之间的桥梁。

  • 首先,浏览器过程接管到用户输出的 URL 申请,浏览器过程便将该 URL 通过 IPC 转发给网络过程。
  • 而后,在网络过程中发动真正的 URL 申请。
  • 接着网络过程接管到了响应头数据,便解析响应头数据,并将数据转发给浏览器过程。
  • 浏览器过程接管到网络过程的响应头数据之后,发送“提交文档 (CommitNavigation)”音讯到渲染过程。
  • 渲染过程接管到“提交文档”的音讯之后,便开始筹备接管 HTML 数据,接收数据的形式是间接和网络过程建设数据管道。
  • 待网络过程中文档数据传输实现,渲染过程会向浏览器过程“确认提交”,这是通知浏览器过程:“曾经筹备好接管和解析页面数据了”。
  • 浏览器过程接管到渲染过程“确认提交”的音讯之后,导航流程就完结了。此时,渲染过程就会开始解析页面和加载子资源了,浏览器过程将开始移除之前旧的文档,而后更新浏览器过程中的页面状态。

3. 渲染流程

渲染流水线

渲染流水线可分为如下几个子阶段:构建 DOM 树、款式计算、布局、分层、绘制、分块、光栅化和合成。

构建 DOM 树(DOM)

浏览器无奈间接了解和应用 HTML,所以要将其转化为浏览器可能了解的解构 —— 通过 HTML 解析器解析,输入树状构造的 DOM

款式计算(Style)

目标是计算 DOM 节点中的每个元素具体款式,可分为三步

  • 渲染引擎把 CSS 文本转为浏览器可了解的构造 ——styleSheets 样式表
  • 标准化样式表中的属性值。这是因为渲染引擎无奈了解 CSS 文本中的各种属性值,这些值会被转为标准化的计算值(例如 {color: blue} → {color: rgb(0, 0, 225)}、{font-weight: bold} → {font-weight: 700}
  • 计算出 DOM 树中每个节点的具体款式,计算过程恪守 CSS 的继承和层叠规定,被保留在 ComputedStyle 构造内

布局阶段(Layout)

计算 DOM 树中可见元素的几何地位信息,包含创立布局树和布局计算两个阶段

  • 创立布局树
    • 遍历 DOM 树中的所有须要渲染节点,并增加到布局树中
    • 不可见的节点如 head 标签下的全部内容,display: none 的标签等会被疏忽
  • 布局计算
    • 计算 DOM 节点的地位坐标,布局运算的后果会被写回布局树中

分层(Layer)

针对页面中的简单成果,例如简单的 3D 变换、页面滚动、z 轴排序等,渲染引擎将为特定节点生成专用的图层,并生成一颗图层树(Layer Tree)

领有层叠上下文属性的元素会被晋升为独自的一层;须要剪裁的中央也会被创立为独自的图层

留神,并非布局树的每个节点都蕴含一个图层,一个节点能够间接或间接地属于一个层,例如一个节点能够从属于父节点的图层

图层绘制(Paint)

渲染引擎会对图层树中每个图层进行绘制,将一个图层的绘制拆分成很多小的绘制指令,而后把这些指令按程序组成一个待绘制列表

栅格化(生成位图)

绘制列表筹备好后,主线程将其提交给合成线程,理论的绘制操作由渲染引擎中的合成线程来实现

  • 合成线程会依据视口地位和大小,将图层(layer)划分为块(图块 tile)
  • 合成线程会依照视口左近的图块来优先生成位图,理论生成位图的操作由栅格化(将图块转换为位图)来执行,图块是栅格化的最小单位
  • 渲染过程会保护一个栅格化的线程池,栅格化过程通常都会应用 GPU 来减速生成,应用 GPU 生成位图的过程叫做疾速栅格化,生成的位图被保留在 GPU 内存中

合成与显示

  • 所有图块都被栅格化后,合成线程将生成绘制图块命令 DrawQuad 提交给浏览器过程
  • 浏览器过程中 viz 组件接管 DrawQuad 命令,依据此命令,将其页面内容绘制在内存中,最初再显示到屏幕上
流水线总结
  • 渲染过程将 HTML 内容转换为可能读懂的 DOM 树结构。
  • 渲染引擎将 CSS 样式表转化为浏览器能够了解的 styleSheets,计算出 DOM 节点的款式。
  • 创立布局树,并计算元素的布局信息。
  • 对布局树进行分层,并生成分层树。
  • 为每个图层生成绘制列表,并将其提交到合成线程。
  • 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
  • 合成线程发送绘制图块命令 DrawQuad 给浏览器过程。
  • 浏览器过程依据 DrawQuad 音讯生成页面,并显示到显示器上。
回流和重绘

基于上述浏览器的渲染原理,咱们能够了解回流和重绘是如何对浏览器性能造成影响的。因为浏览器渲染页面默认应用流式布局模型,当某个 DOM 或 CSS 几何属性产生扭转后,文档流就会受到稳定,就须要对 DOM 从新进行计算,从新布局页面,引发回流。

更新元素几何属性 —— 回流

  • 几何属性的批改会触发浏览器从新布局(Layout & Layer),渲染树须要从新生成,解析起初的一系列子阶段
  • 因而回流须要更新残缺的渲染流水线,开销是最大的

更新元素绘制属性 —— 重绘

  • 绘制属性的批改并没有导致几何地位的变动,所以不会导致布局阶段的执行,会间接进入绘制阶段,而后执行起初的子阶段
  • 重绘操作相比回流省去了布局和分层阶段,效率高于回流

GPU 减速 —— 间接合成

  • 如果更改的属性不须要布局和绘制,渲染引擎会跳过布局和绘制,间接进入非主线程 —— 合成线程执行后续合成操作(比方利用 CSS3 的 transform、opacity、filter 这些属性就能够实现合成成果)
  • 例如,应用 CSS transform 实现动画成果的渲染流水线如下:一是避开了重绘、回流,因而避开了布局和绘制阶段;二是间接在非主线程执行合成动画操作,未占用主线程资源。相比于重绘和回流,合成大大晋升了绘制效率

Reference

  • 浏览器工作原理与实际
  • 浏览器过程架构的演变 &version=13020110&nettype=WIFI&lang=zh_CN&fontScale=100&exportkey=n_ChQIAhIQGRRXFZ2dXQmFA2Bx5wQ4oBKAAgIE97dBBAEAAAAAAOFZNG6p7%2BUAAAAOpnltbLcz9gKNyK89dVj0RmL9G6zZTdJ1mZshRcBg33o4bJEPjfSX4iFReWCjilqk0NfpL0h1iqYKkX2DdW6yD0Adc4JldMIlENpdopQIarHLIcAACAIRLaSzIqVEbSy5JLdxC4wsdBcQ45Ql0oUR6jPwx7%2FIvQ40tphDDC3%2ByysOom29zfOo99XihFQ13nDQARASxLec1XBIK4vt6hKJwK1DVvZvNjCymwWdBeXRAG1acroj2axfwR4dzK161v9LTf9%2BMWeBD%2Bh%2FvEGKWvIRLLB0n8twV5OzxPdRqza4JjY5KY0kXWIpR7o%3D&acctmode=0&pass_ticket=NROenW8KktFdpx%2FehWWP2BcPvnem3EVXgzUh1htgRSOooPPCrE4swwsoZDu1C8jdABIA6JxLm7%2Ffo6AQWCBOmQ%3D%3D&wx_header=0&fontgear=2.000000)

对于本文
作者:@低垂
原文:https://mp.weixin.qq.com/s/6Q…

正文完
 0