Chrome 架构
进程与线程
进程
资源分配的基本单位,程序执行时的一个实例
线程
程序执行的最小单位
区别
进程是资源分配的最小单位,线程是程序执行的最小单位
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此 CPU 切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点
但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间
单进程浏览器架构
进程包含 网络、插件、js 运行环境、渲染引擎等模块
缺点
- 不稳定
一个模块的崩溃会引起整个浏览器的崩溃
不流畅
不安全
多进程浏览器架构
最新的 Chrome 浏览器包括:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程
浏览器进程
界面显示、用户交互、子进程管理,同时提供存储等功能
渲染进程
核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下
GPU 进程
UI 界面都选择采用 GPU 来绘制
网络进程
主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程
插件进程
主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响
渲染流程
整个渲染流程分为: 构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成
- 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。
- 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。
- 创建布局树,并计算元素的布局信息。
- 对布局树进行分层,并生成分层树。
- 为每个图层生成绘制列表,并将其提交到合成线程。
- 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
- 合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
- 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上
构建 DOM 树
解析 HTML 输出 DOM 树
样式计算
通过 样式表, CSS 继承规则,CSS 层叠规则 计算出每个 DOM 节点的具体样式
解析 CSS 文件
标准化样式表属性
计算 DOM 节点样式
布局
创建布局树
遍历 DOM 树中所有可见节点,并添加到布局中
布局计算
计算节点坐标
分层
拥有层叠上下文属性的元素会被提升为单独的一层
- position: fixed
- z-index: 2
- filter
- opacity
需要裁剪的地方也会被创建为图层
图层绘制
栅格化
记录绘制顺序和绘制指令的列表
合成与显示
渲染优化
重排
布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
元素的几何属性修改会触发浏览器重新布局
- 添加或删除可见的 DOM 元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
- 浏览器的窗口尺寸变化
重绘
当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制
元素绘制属性变化, 触发重绘, 重绘省去了布局和分层阶段,执行效率高于重排
- 颜色的修改
- 文本方向的修改
- 阴影的修改
直接合成阶段
无需布局和绘制, 只执行合成操作
事件机制
浏览器事件机制是描述 JS 与 HTML 的交互过程,他们之间的交互是通过事件完成的,而事件流描述了 页面接受事件的顺序
事件流
事件冒泡
事件冒泡是由 IE 团队提出来的,是从交互元素开始触发事件,然后冒泡到顶级元素 document
事件捕获
事件捕获是由 Netscape 团队提出来的 事件解决方案,和事件冒泡相反,事件捕获是由顶级元素 document 接受事件,向下传播到交互元素,在事件捕获阶段我们可以拦截事件
DOM 事件流
DOM 事件流分为三个阶段:事件捕获、目标元素、事件冒泡,先事件捕获,为提前拦截事件提供可能,再到达目标元素,最后是事件冒泡
事件处理程序
HTML 事件处理程序
写在 HTML 标签中的函数
DOM0 事件处理程序
获取 DOM 元素,然后绑定事件处理函数, 函数作用域在 DOM 元素中, this 也指向这个对象
无法同时添加多个事件, 无法控制元素事件流
DOM2 事件处理程序
通过事件监听的方式绑定事件处理函数, 作用域指向当前元素
addEventListener 添加, removeEventLinstener 移除
IE 事件处理程序
与 DOM2 级事件处理程序相似, 通过 attachEvent 绑定事件函数, detachEvent 解绑, IE8 之前的版本只支持 冒泡事件流,无第三个参数
作用域在全局中, 指向 window
事件对象
DOM 中发生事件时, 所有相关信息都会被收集并存储在 event 对象中, 包含 DOM 元素, 事件类型, 事件相关数据
event.preventDefault()
阻止默认事件行为, 或者函数 return false 也能阻止
event.stopPropagation()
阻止事件冒泡, 事件捕获
event.stopImmediatePropagation()
既能阻止事件冒泡, 也能阻止同类型其他事件监听器触发
event.target
触发事件的元素
event.currentTarget
事件监听者
事件委托
利用事件冒泡机制, 使用一个事件处理程序管理一种类型的事件