【浏览器】简单总结一下浏览器工作原理

本文详细解释了HTML、CSS、JavaScript在浏览器中的获取、解析和呈现过程,涉及进程、线程、浏览器进程划分,以及渲染、事件处理和异步任务的执行机制,包括ServiceWorker的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 前言

        本篇就从HTML、CSS、JavaScript获取、解析,到最终呈现在屏幕上的浏览器运行过程,简单总结一下。

2. 进程和线程,以及浏览器中的进程
各类说明
进程

描述:

1. 1个进程占用一块内存空间

2. 进程之间不共享内存,需要通过进程间通信IPC交换数据,1个进程至少有一个主线程

3. 如果需要执行多个程序代码,由主线程开启更多线程,辅助完成任务

关系:进程和线程,是一对多的关系

线程

描述:

1. 线程是具体用来运行程序代码

2. 1个进程中的多个线程共享内存

协程<略>
纤程可理解为协程的一种实现

        浏览器器分为:单进程浏览器和多进程浏览器,针对多进程浏览器:

进程负责任务
Browser Process

a. 处理地址栏、书签栏、前进/后退按钮等模块的任务

b. 处理一些底层系统交互,如:网络请求、文件访问

Renderer Process

处理网页呈现相关任务

GPU Process

处理GPU相关任务

Plugin Process

处理和插件相关的任务

以上进程可能还会细分到:网络进程Network Process、存储进程Storage Process、UI进程UI Process、设备进程Device Process,也可能以线程形式存在于各个进程中。

3. 导航过程(Browser Porcess)

        Browser Process的核心功能是处理用户和浏览器之间的交互

Browser Process中的线程负责任务
UI Thread处理浏览器上的功能按钮及输入框
Network Thread处理网络请求等任务
Storage Thread处理文件访问等任务

  • Step 1:输入地址:UI thread处理地址栏用户输入。
  • Step 2:开始导航:用户回车后,UI thread通知Network thread发起网络请求,获取网页文件,以及控制浏览器Tab上的spinner展示。
  • Step 3:读取响应:Network Thread根据返回的HTTP报文头Content-Type判断响应内容的格式。(如果是HTML格式,会将HTML数据传给Renderer Process;如果是文件,会将数据传给下载管理器。)
  • Step 4:查找渲染进程:Network Thread确认可导航到请求网页,通知UI Thread数据已准备好,UI Thread会查找一个Renderer Process进行网页渲染。(UI Thread可能会提前查找和启动一个Renderer Process)
  • Step 5:确认导航:数据准备好了,Renderer Process也准备好了,Browser Process向Renderer Process发送IPC消息来确认导航,Renderer Process渲染后会给Browser Process回复渲染确认消息,导航结束,页面开始加载。此时,地址栏会更新,展示出新页面的网页信息。history tab 会更新,可通过返回键返回导航来的页面,为了让关闭 tab 或者窗口后便于恢复,这些信息会存放在硬盘中。
  • Step 6:最后:等Renderer Process渲染结束,会发送IPC消息到Browser Process,UI Thread会停止展示Tab中的。

注:JS代码由Renderer Process控制,浏览网页内容,大部分时间不涉及其它进程,beforeunload事件涉及Browser Process通知Renderer Process进行相关检查,对事件进行处理。

如果导航由Renderer Process触发(比如在用户点击某链接,或者JS执行 `window.location = "http://newsite.com" ` )Renderer Process会首先检查是否有 `beforeunload` 事件处理器,导航请求由Renderer Process传递给 Browser process。

如果导航到新的网站,会启用一个新的Renderer Process来处理新页面的渲染,老的进程会留下来处理类似 `unload` 等事件。

除了上述流程,有些页面还拥有 Service Worker (服务工作线程),Service Worker 让开发者对本地缓存及判断何时从网络上获取信息有了更多的控制权,如果 Service Worker 被设置为从本地 cache 中加载数据,那么就没有必要从网上获取更多数据了。

值得注意的是 service worker 也是运行在渲染进程中的 JS 代码,因此对于拥有 Service Worker 的页面,上述流程有些许的不同。

当有 Service Worker 被注册时,其作用域会被保存,当有导航时,network thread 会在注册过的 Service Worker 的作用域中检查相关域名,如果存在对应的 Service worker,UI thread 会找到一个 renderer process 来处理相关代码,Service Worker 可能会从 cache 中加载数据,从而终止对网络的请求,也可能从网上请求新的数据。

4. 渲染过程(Renderer Process)

        Renderer Process的核心功能是将HTML,CSS,JS转换为用户可交互的web页面

Renderer Process中的线程负责任务
Main Thread

主线程(最忙的线程)

1. 解析HTML

2. 解析CSS

3. 计算样式

4. 布局

5. 处理图层

6. 画页面 60次/秒

7. 执行全局JS代码

8. 执行绑定的事件处理函数

9. 执行计时器中的回调函数

...

Worker Thread工作线程
Compositor Thread排版线程
Raster Thread光栅线程

Step 1:解析HTML、CSS,生成DOM Tree和Style Sheets

当Renderer Process接收到导航确认信息,开始接收HTML数据

1. Main Thread的HTML解析器解析HTML文本,生成DOM Tree,保存在浏览器内存中

注:开启预解析线程,分析HTML中包含的JS、图片、CSS等资源,需要从网络或缓存中获取,Main Thread在构建DOM的过程会逐一请求它们,为了加速,preload scanner会同时运行,比如HTML中存在<img> <link>等标签,preload scanner会将请求传递给Browser Process中Netwokr Thread进行相关资源下载

2. 解析遇到的CSS(内联样式、<style>、<link>),CSS解析器对CSS进行解析,生成CSSDOM(StyleSheets)计算样式(css样式的继承、层叠规则)、转换样式中的属性值、基于选择器计算DOM中每个节点的具体样式,未提供CSS的话,浏览器对每个元素使用它默认样式。

3. JS下载与执行:当遇到<script>标签,Renderer Process会停止解析HTML文档,而去加载、解析、执行JS代码。停止解析HTML,是因为JS可能会改变DOM结构。如果<script>中async或defer属性,浏览器则会异步加载和执行JS代码,则不会阻塞渲染。

css解析和HTML解析并行,不会阻塞HTML解析,但阻塞页面渲染。

Step 2:生成渲染树 Render Tree

DOM树 + Style Sheets -> Render Tree

Step 3生成布局树 Layout Tree

DOM和计算样式都有了,还需要知道每个节点在页面上的位置,布局就是找到所有元素的几何关系的过程:遍历DOM及相关元素的计算样式,Main Thread会构建出包含每个元素的坐标信息以及盒子大小的布局树(仅包含页面可见元素,包含伪元素)

Step 4:绘制 Painting

知道了DOM、计算样式、位置信息,还需要知道不同元素绘制的先后顺序,Main Thread遍历布局树,创建绘制记录(Paint Records),绘制记录可看做记录各元素绘制先后顺序的笔记。

Step 5:合成帧:“复合”是一种分割页面为不同的层,并单独栅格化,再组合成帧的技术。不同层的组成由Compositor Thread完成。

Main Thread会遍历布局树来构建层树(Layer Tree),添加了will-change CSS属性的元素,会被看做单独的一层。

一旦层树被创建,渲染顺序被确定,主线程会把这些信息通知给Compositor Thread,合成器线程会栅格化每一层。有的层可以达到整个页面大小,因此Compositor Thread将它们分成多个磁贴,并将每个磁贴发送给Raster Thread,Raster Trhead会栅格化每一磁贴并存储在GPU显存中。

一旦磁贴被光栅化,Compositor Thread会收集称为四边形的磁贴信息以创建合成帧

合成帧随后通过IPC消息传递给Browser Process,由于浏览器的 UI 改变或者其它拓展的渲染进程也可以添加合成帧,这些合成帧会被传递给GPU 用以展示在屏幕上,如果滚动发生,合成器线程会创建另一个合成帧发送给GPU。

合成器的优点在于,其工作无关主线程,Compositor Thread不需要等待样式计算或者 JS 执行,这就是为什么合成器相关的动画 最流畅,如果某个动画涉及到布局或者绘制的调整,就会涉及到主线程的重新计算,自然会慢很多。

5. 浏览器对事件的处理

        当用户在屏幕上触发诸如touch等手势时,首先收到手势信息的是Browser Process,不过Browser Process只会感知到在哪里发生了手势,对tab内内容的处理还是由Renderer Process控制的。

事件发生时,Browser Process会发送事件类型及相应的坐标给Renderer Process,Renderer Process随后找到事件对象并执行所有绑定在其上的相关事件处理函数。

前文中,我们提到过合成器可以独立于主线程之外通过合成栅格化层平滑的处理滚动。如果页面中没有绑定相关事件,组合器线程可以独立于主线程创建组合帧。如果页面绑定了相关事件处理器,主线程就不得不出来工作了。这时候合成器线程会怎么处理呢?

这里涉及到一个专业名词「理解非快速滚动区域(non-fast scrollable region)」由于执行 JS 是主线程的工作,当页面合成时,合成器线程会标记页面中绑定有事件处理器的区域为 non-fast scrollable region ,如果存在这个标注,合成器线程会把发生在此处的事件发送给主线程,如果事件不是发生在这些区域,合成器线程则会直接合成新的帧而不用等到主线程的响应。

渲染进程的Main Thread

DOM Tree->Computing Style->Layout Tree->Paint绘制记录->Layer Tree

(将绘制记录和Layer传给合成器线程)

Compositor Thread   Raster Thread                                          Compositor Thread 

图层分成更小图块 -> 栅格化图块,生成draw quads图块信息->合成器帧 -> 浏览器进程 -> GPU进程

6. 事件循环

        如上“渲染过程”的表格所示,渲染进程最忙的是渲染主线程,需要处理这么多任务,如何进行调度?当然是通过排队的方式进行。

1. 渲染主线程会进入无限循环。

2. 每次循环会检测消息队列中是否存在任务,有,则取出第1个任务执行,执行完进入下次循环;没有,则进入休眠状态。

3. 其他线程,可随时向消息队列末尾添加任务,添加任务时,如果主线程休眠,则唤醒让主线程继续循环取出任务去执行。

注:消息队列不止一个,常见的有:微队列、延时队列、交互队列

以上过程被称为事件循环

异步任务:

  • 计时器结束时执行的任务,setTimeout、setInterval
  • 网络通信完成后执行的任务,XHR、fetch
  • 用于操作后需要执行的任务,EventListener

如果渲染主线程一直等待这些任务时间点的到来,那就会一直处于阻塞状态,表示就是浏览器卡死。浏览器选择用异步来解决这个问题。

因为JS运行在渲染主线程中,所以是单线程语言。而且渲染主线程还有许多其他工作,如渲染页面、执行全局JS。

任务没有优先级,在消息队列中先进先出(FIFO),但消息队列有优先级

  1. 每个任务都有一个任务类型,同一类型任务必须在同一个队列;不同类型的任务可以分属不同的队列。(一次事件循环中,浏览器可根据实际情况,选择从不同的队列中取出任务执行)
  2. 队列也有VIP,浏览器必须准备好一个微队列,微队列中的任务优先于其他所有任务的执行。
  3. 在目前Chrome浏览器中,至少包含了以下队列:
  • 微队列,存放需要最快执行的任务,优先级最高,主要使用Promise和MutationObserver
  • 交互队列,存放用户操作后产生的事件处理任务,优先级高
  • 延迟队列,存放计时器结束后的回调任务,优先级中

参考文章:

图解浏览器的基本工作原理 - 知乎 (zhihu.com)

浏览器的工作原理 (baidu.com)

【干货】浏览器是如何运作的?_哔哩哔哩_bilibili

注:以上,如有不合理之处,还请帮忙指出,大家一起交流学习~  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值