进程线程
- 什么是进程
一个进程就是一个程序运行的实例。
启动一个程序,操作系统为其分配一块内存,内存中有代码,数据和程序的主线程 PCB 控制块等等。
这样的一个运行环境叫做进程,是资源分配和调度的单位,是 CPU 占用的单位(时间片轮转法+动态优先级)。
MAC 的活动监视器的 “内存” 视角就是内存的分配单位 “进程” 的列表,每个进程有多个线程和一块内存和一个端口,PID 为进程号。
- 线程
单线程就是这个进程只有一个线程,线程是 CPU 调度的最小单位,一个进程下的线程共享进程内存空间,线程的调度是应用层问题,程序进程自己负责,不需要内核的介入。
JS 属于一种单线程语言,一个完整的同步任务执行完毕后才能进行下一步操作,这也是为什么说浏览器脚本执行会阻塞视图更新。
浏览器
现代浏览器是多进程的。
如果单线程浏览器(就连 IE 都是每个标签页新开一个 IE 执行的):
- 一个线程崩了就全崩了
- 页面之间相互阻塞任务
- 页面能拿到整个浏览器的数据
- 浏览器进程中的页面共享进程:浏览器主进程(里面还有IO,file等线程可能未来分离出进程),网络进程,CPU 进程
- 沙箱中的进程:插件进程 / 页面的渲染进程(renderer)
- 同站进程共享:同一个站点的不同页面会相互调用脚本共用进程,有时仍然导致一个页面崩了牵连全崩(比如 BroadCast Channel,service worker, shared worker 等 API 可以实现同源页面通信)
Renderer 进程
页面渲染进程是多线程的,如
JS 引擎线程, HTTP 请求线程,定时器线程,GUI 线程,时间处理线程(event 队列)
- GUI 处理 html 构建 domtree
- stylesheets 层叠样式表:格式化 - 标准化 - 计算优先级确定节点样式
- 整合 domtree + csstree = 渲染树 (DOMnode + nodestyle)
- 根据渲染树,计算节点布局 ( 每个节点的位置 ,layout 树,回流/重排)
- 生成图层树 (layer tree)(以此开始以下流程:repaint 重绘)
- 对每个图层,生成绘制指令(数据命令),commit 这些指令给合成线程绘制。
- 合成线程将每个图层分成若干个图块,根据图块的位置优先级将指令栅格化为位图
-
- 会有一个栅格化子线程池不断的栅格化图块
- 会调用 GPU 加速快速栅格化并将位图保存在显存中
- (栅格化即将矢量绘制指令转为像素位图)
- 栅格化的成果是绘制命令(图形命令)交给浏览器进程,浏览器根据这些指令把页面绘制后发给显卡缓冲区
- 显示器在下一次刷新时将缓冲区图像打在显示器上(掉帧现象就是我要刷新了缓冲区的新图像没算出来)
DOM 树
- 拿到文件的原始字节码,解析成 html5 标准文法。
- 进行词法分析,得到 dom 节点对象
- 构建 dom 树:根据文法标签的节点间关系构建树形数据结构。
( DOMContentLoaded & $(doucument).ready )
CSSOM 树
- css 的计算会阻塞视图,视图的渲染需要 cssom 结果。
- cssom 的构建很消耗性能,而过程中最消耗性能的样式的层叠深度。
- 层叠底层:userAngent 用户代理样式表
- 词法分析:格式化 - 标准化 - 计算优先级
Render 树
- 合并 domTree CSSOMTree ,render tree 包含所有 dom 节点和其样式信息
- 从根部遍历每个 domNode,忽略 link 等非可视节点,忽略 display:none 等不可见节点,每个可见节点在 cssomTree 中找到对应样式,并合并出结果生成 renderTree 的一个节点。
layout 回流(重排 reflow)
- rendererTree 中每个节点和他对应的样式,节点之间的关系已经确定,根据这些数据计算他们相对于 viewport 的位置和大小,生成每个节点实际占用的绝对像素值。
图层树(从这里开始的以下:重绘 repaint)
- 绘制时以图层为单位填充后再压叠。
- 各种 FC 如 BFC 等是平面上的各种元素的排列布局,图层则是垂直方向上的排列布局,两个维度,在layout 树生成时已经完成的各种 FC 的计算,而图层数据则是 layout 树中各个节点的一个属性。
-
- fiexd 定位,既在平面上生成了新的 BFC 使得在平面上布局独立,也生成了新的高优先级图层。
- z-index 属性,改变了节点的图层压叠优先级,但没生成新的 BFC。
- 浏览器一般会对一些影响 rendererTree 较大的节点放在单独的层。
合成 compositing
- 以图层为单位,根据其中节点的绝对像素位置,将其分为图块,图块根据在 viewport 中的相对位置具有不同的优先级,高优先级的图块有限被送至合成线程池(可调用 GPU)进行栅格化,把适量图像信息计算成像素位图。
- 将图块位图结果存在显存中,合成线程收集图块结果中绘制四边形(draw quads 储存位图的位置)信息,选择需要的图块进行合成(图块合成图层并压叠)得到一个完整的渲染帧,合成线程通过 IPC 向浏览器主进程 commit 一个渲染帧。
- “快速滚动区”的滚动操作触发时,合成线程可以独立生成新的渲染帧而不需要等待上级的命令。
-
- 快速滚动区:页面中没有事件绑定的区域。或有事件但事件属性有 passive: true
尾声
- 浏览器主进程收到新的渲染帧,调用显存中的位图结果,压入显卡缓冲区,在下一个刷新时机调换活动区和缓冲区。