Chrome的多进程架构process&thread在说浏览器的多进程架构之前,先说说进程和线程的概念。进程是系统调度和分配资源的基本单位。进程可以被认为是程序的运行实例。当启动一个程序时,操作系统会创建一块内存供程序存放代码、运行数据和执行任务的主线程。我们称这样的运行环境为进程。线程依附于进程,是操作系统识别的最小执行和调度单元。在一个进程中使用多线程并行处理可以提高计算效率。多线程可以并行处理任务,但线程不能单独存在。它由启动和管理的进程组成。JS的操作我们最熟悉的就是线程维度了。下面是进程和线程的一些区别:一个线程附属于一个进程,一个进程可以有多个线程;线程在进程中共享数据。进程中任何一个线程执行出错都会导致整个进程崩溃,之前进程之间不会相互影响。当一个进程关闭时,操作系统会回收该进程占用的内存。进程之间的内容是相互隔离的,只能通过IPC进行通信。我觉得知乎最后一个用火车来比喻进程和线程的例子更形象:进程就像火车,线程就像车厢,一列火车有多个车厢,不同的火车互不干扰,但是一场火在一节车厢里会造成灾难。多个隔间。Chrome架构Chrome浏览器包括:1个Browser主进程、1个GPU进程、1个Utility进程、多个Renderer进程和多个Plugin进程。浏览器主进程(browserprocess):主要负责界面显示、用户交互、子进程管理,还包括网络请求和文件访问。GPU进程:独立于其他进程处理GPU任务。渲染器进程(renderingprocess):核心任务是将HTML、CSS、JavaScript转换成用户可以交互的网页。排版引擎Blink和JavaScript引擎V8都运行在这个过程中。默认情况下,Chrome会为Tab标签创建一个渲染进程。出于安全原因,渲染过程以沙盒模式运行。插件进程:主要负责插件的运行。因为插件很容易崩溃,所以需要通过插件进程进行隔离,保证插件进程的崩溃不会对浏览器和页面造成影响。浏览器渲染机制渲染过程的核心工作是将HTML、CSS和JavaScript转换成用户可以与之交互的网页。在此工作过程中,输入HTML经过一些子阶段,最后输出像素。按照渲染的时间顺序,这些子阶段大致可以分为:构建DOM树、计算样式、布局、分层、绘制、平铺、光栅化和合成。构建DOM树当渲染进程开始接收HTML数据时,主线程开始解析HTML并将其转换为浏览器可以理解的DOM树结构。在DOM树的解析过程中,如果遇到img、css或js资源,主线程会向Browser主进程的网络线程发送请求,获取相应的资源。当解析过程中遇到标签中添加async或defer属性来异步加载执行js代码,避免js阻塞HTML解析。样式计算样式计算的目的是计算DOM节点中每个元素的具体样式。在计算过程中,需要遵循CSS继承和级联两条规则。这个阶段大致可以分为三个步骤来完成:ConvertCSStoThestructurethatthebrowsercanunderstand:当渲染引擎收到CSS文本后,会进行一次转换操作,将CSS文本转换成浏览器可以理解的结构了解-样式表;将样式表中的属性值进行转换,使其标准化:例如rem,这些属性需要将所有的值转换为渲染引擎易于理解的标准化计算值;计算DOM树中每个节点的具体样式。在浏览器中,我们可以通过Computed面板查看当前节点的ComputedStyle。布局有了DOM树和DOM对应的ComputedStyle之后,还不足以展示页面。接下来,需要计算可见元素在DOM树中的几何位置。这个计算过程称为布局。Chrome在布局阶段需要完成两个任务:创建布局树和布局计算。创建布局树:浏览器会遍历DOM树中所有可见的节点,并将这些节点添加到布局树中,不可见的节点会被布局树忽略,如图,span元素设置为显示:none,该元素将被布局树忽略;布局计算:有了布局树,浏览器会计算出布局节点的坐标位置;有了layeredlayouttree,对于一些简单的页面来说绘图条件已经具备了,但是对于我们现代的页面来说,还有很多复杂的效果,比如一些复杂的3D变换,z轴排序的z-index等等。这些场景,渲染引擎也会为了页面显示的正确性,为特定的节点生成专用图层,并生成相应的图层树。应该注意的是,并非每个节点都包含一个层。如果一个节点没有对应的层,那么这个节点就属于父节点所在的层。最终每个节点将直接或间接地属于一个层。通常,满足以下两点才能提升到一个单独的层:具有堆叠上下文属性的元素将被提升到一个单独的层。stackingcontext需要裁剪的地方也会被创建为层(overflow)。我们可以在浏览器的图层面板中看到当前页面的分层:绘制是不够的,确定了DOM树、计算风格和布局树之后再绘制页面,需要有明确的绘制顺序。在这个过程中,主线程会遍历布局树,创建绘制记录。同样,我们可以在浏览器的图层面板中看到当前页面对应图层的绘制记录:光栅化(rasterization)确定布局树并创建图层和对应的绘制顺序后,主线程会发送信息提交到合成线程。合成线程去光栅化每一层。由于我们浏览器的视口是有限的,但是页面的长度可能会很长,有些图层可能会超出视口很多,而用户对页面的感知就是视口维度,所以渲染出来是一种浪费一次整个图层。所以合成线程将图层分块。一旦瓦片可用,合成线程将每个瓦片发送到光栅线程,光栅化每个瓦片并将其存储在GPU内存中。在此过程中,合成线程会优先选择视口中的瓦片提交给光栅线程。合成显示光栅化后,合成线程会创建合成帧,通过IPC通信提交给浏览器进程。浏览器进程收到指令后,会将内存中的内容绘制出来,显示在屏幕上。至此,从接收HTML数据到显示页面的整个过程就结束了。接下来我们结合浏览器的渲染过程,看看什么是重排、重绘、合成。重排、重绘和直接复合重排当我们通过js或者css属性更新元素的几何属性,比如元素的宽高,浏览器会重新触发布局,重新执行后续的所有渲染过程。因此,重新排序是最昂贵的。重绘当我们通过js或者css更新一个元素的绘图属性,比如元素的背景色,文字的颜色等等,此时布局和分层阶段就省略了,只剩下后面的过程执行,因此重绘的成本低于重排的成本。小多了。直接合成为什么要使用CSS3的transform等属性来避免重排和重绘呢?因为此时主线程的整个过程会被完全跳过,执行后续的过程,后续的过程会交给执行线程、光栅线程和GPU进程。不占用主线程的资源被执行,所以效率最高。参考文章https://developer.chrome.com/...https://developer.chrome.com/...https://developer.mozilla.org...https://www.zhihu.com/问...
