现代浏览器架构

May 07, 2021

名词介绍:CPU、GPU、内存和多线程架构

cpu: 中央处理器,分为单核处理器和多核处理器,在现代硬件中,大多是多核处理器。 gpu: 图形处理器,最初被设计为是处理图形的,但随着近年的发展,gpu可以承担更多计算任务。在三层计算机体系结构中,硬件位于底部,操作系统位于中间,应用程序则在最上层。在使用计算机时,应用程序使用操作系统提供的机制在CPU和GPU上运行。

hw-os-app

进程:进程可以通过操作系统,启动另一个进程来执行不同的任务。此时,系统将为新进程分配不同的内存;如果两个进程间需要通信,他们可以利用 IPC(Inter Process Communication)的方式进行通信;当启动一个应用程序时,操作系统会分配内存与执行进程,所有应用的状态都会保存在一块私有的内存空间,当应用关闭了,操作系统就会销毁进程,释放内存。

线程:存在与进程内部,执行进程的部分任务

chrome浏览器架构

可能是一个具有许多不同线程或许多不同进程的进程,只有少数线程能够通过 IPC 进行通信。 浏览器有哪些进程:

  • 1.浏览器进程:控制chrome应用程序,包括地址栏、后退、前进事件等。还有处理网络请求、文件访问等
  • 2.渲染进程:控制选项卡内、页面内容
  • 3.GPU进程:处理来自多个进程的请求
  • 4.插件进程:网站插件的使用 hw-os-app

chrome为什么要使用多线程

  • 1.各个进程互不干扰,每个选项卡有自己的进程,不会因为其他进程的错误导致无法响应
  • 2.安全性与沙盒,对某些进程的权限进行限制,例如,Chrome 浏览器可以对处理用户输入(如渲染器)的进程,限制其文件访问的权限,功能明确清晰。

chrome正在致力于服务化与站点隔离

  • 1.将浏览器程序的每个部分,作为一项服务运行,从而可以轻松拆分为不同的流程或汇总为同一个流程。
  • 2.站点隔离,独立渲染。可以为每个跨网站 iframe 运行单独的渲染器进程,确保一个站点在未经允许下,不能向其他站点访问数据。

在浏览器中输入url,chrome干了什么?

  • 1.处理输入

    当用户在地址栏中输入地址,浏览器进程中的UI线程会先判断输入内容是查询搜索还是url? 在 Chrome 中,地址栏同时具备搜索查询的功能,因此 UI 线程需要解析并确定是将请求发送到搜索引擎,还是发送到待请求的网站。

  • 2.开始导航

    UI线程会进行网络请求,以获取页面内容。网络线程会经历dns查找或和建立TL链接等网络协议。这时,网络线程可能收到301服务器重定向,网络线程就会和UI线程通讯,启动对另一个Url的请求。

  • 3.读取响应

    开始接收响应体后,网络线程会先读取几个字节。Content-Type响应体会说明数据类型,但由于它可能会丢失或者错误,通过 MIME 类型嗅探,来进一步判断数据类型。

    如果判断是html文件,下一步就是将数据传递给渲染器进程。如果是ZIP文件或其他文件,表示这是下载请求,就会将数据传递给下载管理器。

    网络线程会检查响应数据是否来自安全域名,如果检查到是来自已知的恶意域名,就会发出警告,显示警告页面。

  • 4.查找渲染器进程

    当所有检查执行完以及网络线程确定是定位到哪个网址后,UI线程就会让渲染器进程进行页面渲染。

    因为网络线程处理时间较长,所以在步骤2确定了导航的网址后,UI线程就会启动或者查找复用一个渲染进程,与网络进程同步执行。当网络线程开始接收数据时,渲染器进程已处于待用状态。

  • 5.提交导航

    提交导航,IPC将从浏览器进程发送一个数据流到渲染器进程。因为此处传递的是一个数据流,渲染器进程可以继续从数据流中接收 HTML 数据。一旦浏览器进程监听到渲染器进程中已经确认提交,一次导航就算完成了,接下来就是文档加载阶段。

    此时,地址栏就会更新,安全锁(HTTPS证书安全)和站点设置 UI 会显示新页面的站点信息。选项卡的历史记录将更新,因此后退/前进按钮将允许操作之前的浏览器历史。同时会将历史记录存储在磁盘上,以确保关闭选项卡或窗口后,依然可以浏览历史以及还原窗口。

  • 额外步骤:初始加载完成

    一旦渲染器进程 “完成” 渲染,它就会通过 IPC 将消息通知回浏览器进程(这是在所有页面中的 onload 事件都触发之后执行的)。此时,UI 线程会隐藏选项卡上的加载进度图标。

    这里的 “完成” 之所以加引号,因为客户端 JavaScript 仍然可以加载额外的资源,并在此之后呈现新的视图。

渲染器进程—如何将html、css和js处理成可以与用户交互的网页

渲染器进程的核心工作内容是将html、css和js处理成可以与用户交互的网页。

解析

渲染器进程开始接收html数据后,主线程就开始处理html,将其处理成DOM

子资源加载

为了加快资源加载速度,主线程会启用“预加载扫描”,发现有类似 img 或 link 这样的标签时,会由 HTML 解析器对该资源生成一个 Tokens,然后在浏览器进程中,通过网络或者本地缓存来加载资源。

一个完整的 Web 站点通常会包含图片、CSS 和 JS 等外部资源,这些文件都需要从网络或者本地缓存中加载。主线程可以在解析构建 DOM 的时候,将他们逐个请求。

JS可以阻止解析

当 HTML 解析器遇到script 标签的时候,它会暂停解析 HTML 文档,然后对这个 JS 脚本进行加载、解析和执行。因为js脚本可以改变dom元素,因而HTML 解析器在重新解析 HTML 之前,必须等待 JS 脚本执行。

HTML 遇到 JS 脚本则暂停对 HTML 的解析,这并不是绝对的。script 标签中添加 async 或 defer 标记,然后浏览器会异步加载和运行此 JS 脚本,不会阻断解析。如果需要,也可以使用 JavaScript Modules,还可以通过 rel=“preload” 标签向浏览器明确标记此为重要的资源,将在页面加载完成之后被立刻使用,对于这类资源,它会在页面加载生命周期的早期,被优先加载。

样式渲染

主线程解析css并添加渲染样式。即使不用css,每个dom节点存在默认的样式。

布局

主线程遍历dom树并计算样式,然后创建layout树,在布局树中包含元素的x、y坐标和边框大小的信息。举个例子,如果某个元素设置了 display:none,则该元素将不会出现在布局树中,但是它会出现在 DOM 树中,而如果该元素被设置为 visibility:hidden 则它会存在于布局树中。类似的例子还有 p::before{content:“Hi!“} 这样的伪类,它会存在于布局树中,而不会存在于 DOM 树中。

绘制

拥有 DOM、CSS 和 LayoutTree 仍然不足以渲染页面。假设你正在尝试重绘一幅画,你除了需要知道元素的大小、外观和位置之外,还需要知道它们的绘制顺序。例如z-index属性的设置,因而在这过程中,主线程遍历布局树,然后创建绘制记录。

更新渲染管道

渲染管道(Rendering Pipeline)中最重要的任务,就是在每个步骤开始前,根据前一次操作的结果,来创建新的数据。例如,如果布局树中的某些内容发生更改,则需要为文档的受影响部分重新生成“绘制”顺序。

渲染管道(Rendering Pipeline)中最重要的任务,就是在每个步骤开始前,根据前一次操作的结果,来创建新的数据。例如,如果布局树中的某些内容发生变动,则需要为文档中受影响的部分,重新生成“绘制记录”。

合成

现在浏览器知道页面的结构、元素样式、绘制顺序,要将这些元素转换为屏幕的像素,称为光栅化。

光栅化是将几何数据经过一系列变换后最终转换为像素,从而呈现在显示设备上的过程。

合成

合成是一种将页面的各个元素进行分层,分别光栅化,并在合成器线程中以一个单独的线程合成新页面的技术。如果页面发生滚动,由于图层已经光栅化,因此它需要做的就是合成一个新帧。通过移动图层同时合成新帧,可以以相同的方式实现动画。

分层

为了确定每个元素所在的层,主线程遍历布局树以创建层树(Layer Tree)

光栅和合成,脱离主线程

一旦创建了层树并确定了绘制顺序,主线程就会将该信息提交给合成器线程。合成器线程会光栅化每个图层,一个图层可能想一个完整的页面那么大,因此合成器线程将他们分成图块,并将每个图块发送到光栅线程。光栅线程格式化每个元素,并将他们存储在 GPU 内存中。

hw-os-app

合成器线程可以优先考虑不同的光栅线程,以便 ViewPort(或附近)的元素可以被优先光栅化。图层还具有多个不同分辨率的倾斜度,以便对内容的放大等操作。

一旦元素被光栅化,合成器线程会收集被称为 “绘制矩形(Draw Quads)” 的信息,用以创建一个合成帧(Compositor Frame)。

然后通过 IPC 将合成帧提交给浏览器进程。此时,可以从 UI 线程添加另一个合成帧用于浏览器的 UI 更新,或者从其他渲染器进程中添加扩展。这些合成帧被发送到 GPU 中,用以在屏幕上显示。如果触发滚动事件,合成器线程会创建另一个合成帧发送到 GPU。

合成(Compositor)的好处,是它可以在不影响主线程的情况下完成。合成器线程不需要等待样式计算或者 JS 脚本执行,这就是为什么 “仅合成动画” 被认为是平滑性能的最佳选择。如果需要再次计算不会或者重新绘制,则必须涉及到主线程。


Profile picture

百事可乐

Let it snow, let it snow, let it snow