目录
浏览器进程架构的演化
进程和线程关系图示
进程(Process)
线程(Thread)
协程(Coroutine)
进程&线程&协程核心对比
单进程和多进程浏览器
单进程浏览器编辑
单进程浏览器存在的问题
多进程浏览器
浏览器的主要进程有哪些?编辑
多进程浏览器是如何解决单进程浏览的问题的?
多进程浏览器存在的问题?
浏览器导航流程
1. 用户输入URL
2. 浏览器进程处理用户输入
3. 服务器响应
4. 渲染进程解析HTML
5. 渲染进程解析CSS
6. 构建渲染树
7. 布局(Layout)
8. 绘制(Paint)
9. 合成(Composite)
10. 执行JavaScript
11. 事件处理
12. 资源加载
13. 完成加载
进程间通信(IPC)
浏览器导航全流程示意图
浏览器渲染流程
渲染流水线
1.构建 DOM 树(DOM)
2.样式计算(Style)
3.布局阶段(Layout)
3.1 创建布局树编辑
3.2布局计算
4.分层(Layer)
5.图层绘制(Paint)
6.分块
7.栅格化(生成位图)
8.合成与显示
渲染流水线总结
回流和重绘
更新元素几何属性 —— 回流
更新元素绘制属性 —— 重绘
GPU 加速 —— 直接合成
常用的方法来触发GPU加速
使用3D变换
启用硬件加速的CSS属性
will-change属性
使用backface-visibility
filter属性
避免布局重绘和回流
使用requestAnimationFrame
浅谈浏览器引擎
浏览器引擎跟进程的关系
现代浏览器采用了多进程架构,以提高性能、稳定性和安全性除了渲染进程和合成进程,浏览器还包含其他多种进程以下是一些常见的浏览器进程:
1. 浏览器进程(Browser Process):
负责管理用户界面、网络请求、存储等全局资源
处理用户与浏览器的交互,如打开新标签页、关闭标签页、前进后退等操作
创建和管理其他进程
2. 渲染进程(Renderer Process):
负责处理网页的渲染、JavaScript执行、DOM操作等任务
每个标签页通常对应一个独立的渲染进程,以提高稳定性和隔离性
3. 合成进程(Compositor Process):
负责将多个图层合成最终的屏幕显示
优化动画和滚动性能,减少卡顿
4. GPU进程(GPU Process):
负责处理与图形相关的任务,如3D渲染、视频解码等
通过硬件加速来提升图形处理的效率和性能
5. 插件进程(Plugin Process):
用于处理浏览器插件(如Flash、Silverlight等)的运行
由于插件可能存在安全性和稳定性问题,将其放在独立的进程中可以减少对浏览器主进程的影响
6. 网络进程(Network Process):
负责处理网络请求,如HTTP/HTTPS请求
通过集中管理网络请求,提高网络性能和安全性
7. 存储进程(Storage Process):
负责处理浏览器的存储操作,如IndexedDB、LocalStorage等
通过集中管理存储操作,提高存储性能和安全性
8. 实用工具进程(Utility Process):
用于执行一些辅助任务,如PDF解析、打印等
这些任务通常需要较高的权限,因此放在独立的进程中以提高安全性
9. Zygote进程(Zygote Process):
用于快速创建新的渲染进程
通过预创建一个基础进程,可以快速克隆出新的渲染进程,提高启动速度
10. 沙箱进程(Sandbox Process):
负责管理沙箱机制,限制进程对系统资源的访问权限
通过沙箱机制,即使某个进程被恶意代码利用,其危害也会被限制在一定范围内
11. 扩展进程(Extension Process):
用于处理浏览器扩展的运行
每个扩展通常运行在独立的进程中,以提高稳定性和安全性
12. 服务工作进程(Service Worker Process):
负责处理服务工作线程(Service Worker)的运行
服务工作线程可以处理网络请求、推送通知等后台任务
13. 音频进程(Audio Process):
负责处理音频相关的任务,如音频解码和播放
通过集中管理音频任务,提高音频性能和稳定性
这些进程共同协作,使得现代浏览器能够高效地处理复杂的网页应用,提供更好的用户体验每个进程都有明确的职责,通过进程间通信(IPC)机制进行协作;浏览器进程可以通过Chrome 选项 -> 更多工具 -> 任务管理器查看;
浏览器进程架构的演化
进程和线程关系图示
进程(Process)
- 定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度的基本单位。每个进程都有自己的独立内存空间。
- 特点:
- 每个进程都有自己独立的地址空间和运行环境。
- 进程之间的切换开销较大,因为需要保存和恢复整个CPU的状态(上下文)。
- 进程间通信(IPC)相对复杂,通常需要使用特定的机制如管道、消息队列等。
线程(Thread)
- 定义:线程是进程中的一个实体,是被系统独立调度和分派的基本单位。一个线程不能独立存在,它必须属于一个进程,且一个进程至少包含一个线程。
- 特点:
- 线程共享其所属进程的资源,包括内存空间、文件描述符等。
- 线程间的切换开销比进程小,因为它们共享相同的地址空间。
- 同一进程内的线程可以直接访问该进程的数据和代码,因此线程间的通信更简单高效。
协程(Coroutine)
- 定义:协程是一种用户态的轻量级线程,其调度由程序员自行控制而非操作系统。这意味着你可以更灵活地决定何时暂停或继续执行一个协程。
- 特点:
- 协程的创建和管理成本远低于线程,因为它们不依赖于操作系统的线程或进程调度器。
- 协程之间可以通过简单的函数调用来实现协作式的任务切换,这使得编写异步程序变得更加直观和易于理解。
- 在处理大量并发任务时,使用协程可以有效减少系统资源的消耗。
总结来说,进程、线程和协程分别代表了不同的执行单元级别,从最重的进程到最轻量级的协程,它们各自适合解决不同类型的问题。
用简单的语言来说:
- 进程就像一个“工厂”,它拥有自己独立的资源(比如场地、机器等)。
- 线程是工厂里的“工人”,多个工人(线程)可以在同一个工厂(进程)里工作,共享资源。
- 协程就像是“工人”之间的一种合作方式,他们可以轮流干活,不争不抢,效率更高。
所以:
一个进程可以包含多个线程,而线程内部可以通过协程来协作完成任务。
也可以理解为:
- 进程是“单位”,
- 线程是“员工”,
- 协程是“员工之间的分工合作方式”。
进程&线程&协程核心对比
特性 | 进程 | 线程 | 协程 |
---|---|---|---|
资源隔离 | 完全隔离 | 共享内存 | 共享内存 |
切换成本 | 非常高(ms级) | 较高(μs级) | 极低(ns级) |
调度方 | 操作系统 | 操作系统 | 用户程序 |
内存占用 | MB级 | KB级 | Byte级 |
通信机制 | IPC(管道/消息) | 共享内存 | 共享内存+Channel |
单进程和多进程浏览器
单进程浏览器
单进程浏览器是指所有功能模块(网络、插件、JS 运行环境、渲染引擎、页面等)都运行在同一进程中的浏览器(早期的 IE、Firefox);
单进程浏览器存在的问题
不稳定: 浏览器中的插件运行在浏览器的进程之中,插件的崩溃会引起整个浏览器的崩溃;
渲染引擎通常也是不稳定的,例如复杂的 JS 脚本也会引起渲染引擎的崩溃,最终导致浏览器崩溃。
不流畅: CPU 在某个时间点只能执行某个进程中的某一条线程。由于单进程浏览器中所有的页面的各种模块都在同一线程中运行,即同一时刻只能有一个模块可以执行。
当一个页面的某个模块阻塞了该线程,就会导致整个浏览器失去响应;此外,页面的内存泄漏也会导致单进程浏览器使用时间越长,反应越慢。
不安全: 线程共享进程资源,因而插件就能获取到浏览器运行过程中的数据,以及拥有和浏览器同等的系统权限。
例如,插件可使用 C/C++ 编写,通过插件可以获取到操作系统任意资源;脚本也可以通过浏览器的漏洞来获取系统权限,引发安全问题。
多进程浏览器
Chrome 一问世便使用了多进程的架构,其页面运行在了单独的渲染进程中,插件运行在单独的插件进行中,进程间使用 IPC 进行通信。
浏览器的主要进程有哪些?
多进程浏览器是如何解决单进程浏览的问题的?
不稳定问题解决: 正是由于进程之间相互隔离,当一个页面或者插件崩溃时只会影响当前的进程,不会影响到浏览器和其他页面。
不流畅问题解决: 由于 JS 脚本运行在渲染进程中,即使 JS 阻塞了渲染进程,也只会影响当前页面的渲染,而其他页面的脚本则会运行在他们自己的渲染进程中,不受影响;此外,内存泄漏导致的不流畅问题也会随着一个页面的关闭导致一个进程的结束而解决。
不安全问题解决: 多进程架构的安全沙箱,相当于是操作系统给进程上了一把锁,沙箱中的程序可运行不可写入、不可读取敏感数据。
多进程浏览器存在的问题?
更高的资源占用: 以 Chrome 浏览器为例,其将为每个页面分配单独的渲染进程,为每个插件分配单独的插件进程,因此会消耗更多内存资源。
更复杂的体系架构: 浏览器各个模块之间耦合度高、扩展性差目前的架构较难适应新需。
浏览器导航流程
从用户发出 URL 请求到页面开始解析的过程,叫做导航,是网络加载流程和渲染流程之间的桥梁
浏览器的各个进程通过进程间通信(IPC)机制紧密配合,共同完成将页面呈现给用户的任务。以下是一个详细的流程,说明各个进程如何协作完成这一过程:
1. 用户输入URL
用户在浏览器地址栏输入一个URL并按下回车键。
2. 浏览器进程处理用户输入
- 浏览器进程:接收到用户输入的URL后开始处理。
- DNS解析:将URL中的域名转换为IP地址。
- 建立TCP连接:浏览器与服务器之间建立TCP连接。
- 发送HTTP请求:通过HTTP或HTTPS协议向服务器发送请求,要求获取HTML内容。
3. 服务器响应
- 服务器响应:服务器处理请求,并返回HTML文档。
- 接收响应:浏览器进程接收服务器响应,并将HTML文档传递给渲染进程。
4. 渲染进程解析HTML
- 渲染进程:接收到HTML文档后开始解析,构建DOM树。
- 解析HTML:生成DOM树结构。
5. 渲染进程解析CSS
- 解析CSS:分析CSS文件,构建CSSOM树。
- 构建CSSOM树:包含所有CSS规则。
6. 构建渲染树
- 构建渲染树:结合DOM和CSSOM树,形成渲染树,它包括所有可见的DOM节点及其样式信息。
7. 布局(Layout)
- 布局:计算每个节点在页面上的确切位置和大小。
- 重排(Reflow):确定几何信息如宽度、高度、边距等。
8. 绘制(Paint)
- 绘制:根据渲染树的信息,绘制每个节点到屏幕上。
- 重绘(Repaint):更新视觉信息如颜色、边框、背景等。
9. 合成(Composite)
- 合成进程:负责将绘制好的图层合并成最终显示的内容。此步骤通常由GPU完成以提高性能。
- 图层:为了优化性能,浏览器可能会将某些节点分组到不同的图层中。
10. 执行JavaScript
- 执行JavaScript:渲染进程解析并执行页面中的JavaScript代码。
- 动态修改:JavaScript可以动态地修改DOM和CSSOM,触发重新布局和绘制。
11. 事件处理
- 事件处理:浏览器进程处理用户交互事件(如点击、滚动)。
- 触发JavaScript:这些事件可触发JavaScript代码执行,进一步影响DOM和CSSOM,导致重新布局和绘制。
12. 资源加载
- 资源加载:继续加载页面引用的其他资源,如图片、字体、视频等。
- 异步加载:这些资源可能异步加载,不会阻塞页面的初始渲染。
13. 完成加载
当所有资源都加载完毕,页面完全渲染并在屏幕上显示。
进程间通信(IPC)
在整个过程中,不同进程通过IPC机制协作:
- 浏览器进程与渲染进程间的文档传递和结果反馈
- 渲染进程与合成进程间的图层信息交换
- 渲染进程与GPU进程间的图形任务处理
- 浏览器进程与网络进程间的请求和响应管理
- 浏览器进程与存储进程间的存储操作处理
这种多进程架构提高了浏览器的性能、稳定性和安全性,确保了页面能够高效准确地展示给用户。
浏览器导航全流程示意图
浏览器渲染流程
渲染流水线
渲染流水线可分为如下几个子阶段:1.构建 DOM 树、2.样式计算、3.布局、4.分层、5.绘制、6.分块、7.光栅化、8.合成
1.构建 DOM 树(DOM)
浏览器无法直接理解和使用 HTML,所以要将其转化为浏览器能够理解的解构 —— 经过 HTML 解析器解析,输出树状结构的 DOM
当浏览器接收到服务器响应的HTML文档后,它开始解析这些标记以生成一个文档对象模型(DOM)。DOM是一个表示文档结构的树状结构,其中每个节点代表文档的一部分(如元素、属性或文本)
2.样式计算(Style)
目的是计算 DOM 节点中的每个元素具体样式,可分为三步
-
渲染引擎把 CSS 文本转为浏览器可理解的结构 ——styleSheets 样式表
-
标准化样式表中的属性值。这是由于渲染引擎无法理解 CSS 文本中的各种属性值,这些值会被转为标准化的计算值(例如
{color: blue} → {color: rgb(0, 0, 225)}、{font-weight: bold} → {font-weight: 700}
) -
计算出 DOM 树中每个节点的具体样式,计算过程遵守 CSS 的继承和层叠规则,被保存在 ComputedStyle 结构内
在这一步骤中,浏览器解析CSS并确定哪些样式应用于DOM中的各个元素。这一过程包括匹配选择器、层叠(决定哪个规则优先)以及继承(某些样式会自动应用到子元素上)等步骤。结果是一个包含每个元素最终样式的“render tree”
3.布局阶段(Layout)
计算 DOM 树中可见元素的几何位置信息,包括创建布局树和布局计算两个阶段;
布局阶段也被称为reflow,是指根据“render tree”来计算每个元素的确切位置和大小。这是基于当前窗口尺寸以及任何明确设置的宽高值进行的。布局的结果是一组框,它们准确地描述了每个元素在页面上的位置和尺寸
3.1 创建布局树
-
遍历 DOM 树中的所有需要渲染节点,并添加到布局树中;
-
不可见的节点如 head 标签下的全部内容,display: none 的标签等会被忽略;
-
3.2布局计算
- 计算 DOM 节点的位置坐标,布局运算的结果会被写回布局树中
4.分层(Layer)
针对页面中的复杂效果,例如复杂的 3D 变换、页面滚动、z 轴排序等,渲染引擎将为特定节点生成专用的图层,并生成一颗图层树(Layer Tree);
这样,当某个部分发生变化时,只有相关的图层需要重绘,而不是整个页面。这类似于图像编辑软件中的图层概念。
拥有层叠上下文属性的元素会被提升为单独的一层;需要剪裁的地方也会被创建为单独的图层
注意,并非布局树的每个节点都包含一个图层,一个节点可以直接或间接地属于一个层,例如一个节点可以从属于父节点的图层;
5.图层绘制(Paint)
绘制阶段涉及到实际填充像素的过程,即把页面的视觉表现转化为屏幕上的像素。这包括文本、颜色、图像、边框和阴影等。不过,这一步并不考虑元素的深度或顺序,所有元素都是平面化处理的;
渲染引擎会对图层树中每个图层进行绘制,将一个图层的绘制拆分成很多小的绘制指令,然后把这些指令按顺序组成一个待绘制列表
6.分块
分块是进一步将图层分割成更小的部分,以便于后续的光栅化处理。这有助于提高效率,特别是对于大型页面,因为它允许浏览器并行处理多个部分
7.栅格化(生成位图)
绘制列表准备好后,主线程将其提交给合成线程,实际的绘制操作由渲染引擎中的合成线程来完成;
光栅化是将矢量图形或较高层次的命令转换为像素网格的过程。在这个阶段,浏览器会将页面的每一部分转换为显示器能够呈现的位图格式;
-
合成线程会根据视口位置和大小,将图层(layer)划分为块(图块 tile)
-
合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作由栅格化(将图块转换为位图)来执行,图块是栅格化的最小单位
-
渲染进程会维护一个栅格化的线程池,栅格化过程通常都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫做快速栅格化,生成的位图被保存在 GPU 内存中
8.合成与显示
-
所有图块都被栅格化后,合成线程将生成绘制图块命令 DrawQuad 提交给浏览器进程
-
浏览器进程中 viz 组件接收 DrawQuad 命令,根据此命令,将其页面内容绘制在内存中,最后再显示到屏幕上
-
这个阶段负责将所有的图层和分块组合在一起,并按照正确的顺序显示出来。考虑到可能存在的透明度和z-index等因素,这个阶段确保了页面按照预期的方式显示
渲染流水线总结
-
渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。
-
渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。
-
创建布局树,并计算元素的布局信息。
-
对布局树进行分层,并生成分层树。
-
为每个图层生成绘制列表,并将其提交到合成线程。
-
合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
-
合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
-
浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。
回流和重绘
基于上述浏览器的渲染原理,我们可以理解回流和重绘是如何对浏览器性能造成影响的。由于浏览器渲染页面默认使用流式布局模型,当某个 DOM 或 CSS 几何属性发生改变后,文档流就会受到波动,就需要对 DOM 重新进行计算,重新布局页面,引发回流。
更新元素几何属性 —— 回流
-
几何属性的修改会触发浏览器重新布局(Layout & Layer),渲染树需要重新生成,解析后来的一系列子阶段;
-
因此回流需要更新完整的渲染流水线,开销是最大的;
更新元素绘制属性 —— 重绘
-
绘制属性的修改并没有导致几何位置的变化,所以不会导致布局阶段的执行,会直接进入绘制阶段,然后执行后来的子阶段;
-
重绘操作相比回流省去了布局和分层阶段,效率高于回流;
GPU 加速 —— 直接合成
-
如果更改的属性不需要布局和绘制,渲染引擎会跳过布局和绘制,直接进入非主线程 —— 合成线程执行后续合成操作(比如利用 CSS3 的 transform、opacity、filter 这些属性就可以实现合成效果);
-
例如,使用 CSS transform 实现动画效果的渲染流水线如下:一是避开了重绘、回流,因此避开了布局和绘制阶段;二是直接在非主线程执行合成动画操作,未占用主线程资源。相比于重绘和回流,合成大大提升了绘制效率;
在前端开发中,触发GPU加速可以显著提升页面的性能,特别是在处理动画、滚动、3D变换等场景时
常用的方法来触发GPU加速
使用3D变换
使用translate3d(x, y, z)或translateZ(z)而不是普通的translate(x, y)。这会强制浏览器将元素及其子元素提升到一个独立的图层上,从而利用GPU进行渲染。
启用硬件加速的CSS属性
除了3D变换外,其他一些CSS属性也能触发GPU加速,如transform和opacity。当你对这些属性应用动画时,浏览器可能会选择使用GPU加速。
will-change属性
will-change是一个CSS属性,它向浏览器指示某个元素将会发生的变化(如内容、位置、堆叠顺序等),这样浏览器可以在变化实际发生之前做出优化,比如提前创建一个新的图层。例如:will-change: transform; 或 will-change: opacity;
使用backface-visibility
设置backface-visibility: hidden;也可以触发GPU加速,尤其是在做翻转或旋转效果时。
filter属性
应用CSS滤镜(filter)也可以促使浏览器使用GPU进行加速处理。例如模糊效果filter: blur(5px);
避免布局重绘和回流
尽量减少那些会引起大量重绘和回流的操作,比如频繁修改元素的尺寸、位置或者样式。
应该尝试批量更新样式或者使用transform和opacity,因为它们通常不会引起重绘或回流。
使用requestAnimationFrame
在执行复杂的动画时,使用requestAnimationFrame()代替setTimeout或setInterval,它可以确保动画帧与浏览器的刷新率同步,提高动画流畅度,并且有助于优化性能。
需要注意的是,虽然上述方法可以帮助你触发GPU加速,但过度使用可能导致内存消耗增加,甚至可能降低性能。因此,在实际项目中应当谨慎使用,并根据具体情况进行性能测试和调优。
浅谈浏览器引擎
浏览器是通过多种引擎协同工作来解析和展示网页内容的。几个关键引擎和技术组件对于前端开发至关重要:
-
JavaScript引擎:用于解释和执行JavaScript代码。每个浏览器都有自己的JavaScript引擎(例如,V8引擎在Google Chrome和Node.js中使用)。
-
HTML渲染引擎(也称作布局引擎或浏览器引擎):负责获取标记内容(如HTML、XML等),构建DOM树,并将其与CSS一起用于页面布局和格式化。常见的HTML渲染引擎包括WebKit(Safari)、Blink(Chrome, Opera) 和 Gecko (Firefox)。
-
CSS引擎:虽然它通常不是单独存在的,而是作为HTML渲染引擎的一部分,但它的功能专注于解析CSS规则,并将这些样式应用到文档对象模型(DOM)上。
-
图像解码器:用于处理和显示网页上的各种图像格式,比如JPEG、PNG、GIF等。
-
字体渲染引擎:负责将文本转换为屏幕上显示的字形,处理字体文件(如TrueType, OpenType)并支持文本排版和国际化文本显示。
-
多媒体引擎:用于播放音频和视频内容。现代浏览器支持HTML5中的
<audio>
和<video>
标签,不需要额外的插件即可播放媒体文件。 -
网络引擎:管理HTTP/HTTPS请求,缓存机制,以及安全连接等,确保数据能够高效且安全地传输。
-
安全引擎:确保用户的安全性,包括防止跨站脚本攻击(XSS),跨站请求伪造(CSRF)等安全威胁。
这些引擎共同作用,使得浏览器能够加载、呈现网页,并提供交互式体验给用户。随着技术的发展,浏览器也在不断地优化这些引擎,以提高性能、安全性和用户体验。
浏览器引擎跟进程的关系
浏览器的架构设计通常涉及多个进程和线程,以实现高效、稳定以及安全的网页浏览体验。不同的引擎在浏览器中可能会分布在不同的进程或线程中工作,以便更好地管理资源和提升性能。以下是一些基本概念及其与不同引擎之间的关系:
-
多进程架构:现代浏览器通常采用多进程架构来提高稳定性和安全性。这意味着浏览器的不同部分(如标签页、插件、扩展等)运行在不同的进程中。例如,在Chrome浏览器中,有一个主进程负责管理其他各种子进程,包括渲染进程、GPU进程、网络服务进程等。
-
渲染进程:这是处理网页内容的主要进程,包括HTML引擎、CSS引擎、JavaScript引擎等。每个标签页一般都会有自己的渲染进程,这样即使一个标签页崩溃了,也不会影响到其他标签页。渲染进程中包含了布局、绘制和JavaScript执行等操作。
-
主线程和工作线程:
- 主线程:几乎所有与页面显示相关的任务都在主线程上执行,包括解析HTML、构建DOM树、计算样式、布局、绘制以及执行大部分JavaScript代码。
- 工作线程:为了防止某些耗时的任务(比如大型脚本执行或者网络请求)阻塞主线程,从而导致页面响应变慢,浏览器引入了工作线程的概念。这包括Web Workers,它允许你在后台线程执行JavaScript代码,而不会干扰主线程上的用户界面更新。
-
GPU进程:用于加速图形处理任务,如3D变换、视频解码等。通过将这些任务交给专门的GPU进程,可以减轻CPU负担并提高性能。
-
网络进程:负责所有的网络活动,比如HTTP请求。它独立于渲染进程运行,确保即使页面加载失败或出错,也不影响浏览器的整体稳定性。
-
安全性和隔离性:通过将不同的网站内容分配给不同的渲染进程,并利用操作系统提供的安全特性,浏览器能够有效地隔离各个网站,减少跨站攻击的风险。
综上所述,浏览器中的各个引擎是通过分布在不同的进程和线程上来工作的,这样的设计不仅提高了浏览器的稳定性和安全性,还能更高效地利用系统资源,为用户提供流畅的浏览体验。
参考链接:javascript - 图解浏览器的多进程渲染机制 - 大前端技术栈 - SegmentFault 思否