浏览器进程和线程:前端开发工程师的必修课

2,026 阅读15分钟

浏览器是我们日常使用的最常见的软件之一,它为我们提供了访问互联网的窗口。但是,你有没有想过浏览器是如何工作的呢?浏览器的内部是由多个进程和线程组成的,它们负责不同的功能和任务,相互协作,共同完成浏览器的各种操作。在本文中,我们将深入了解浏览器的进程和线程的概念和原理,以及它们对Web前端开发的影响和意义。

理解进程和线程

进程(process)和线程(thread)是操作系统的基本概念

进程

是计算机中正在运行的程序的实例。这些程序可能是你打开的应用程序,例如浏览器、文本编辑器或游戏。当你启动一个应用程序时,计算机会为它创建一个进程,它可以使用计算机的资源,例如内存、CPU 和存储设备。每个进程都有自己的地址空间系统资源,因此不同的进程之间是隔离的。这样可以确保一个程序的崩溃不会影响其他程序的运行

线程

是进程中的执行单元,可以看作是轻量级的进程。一个进程可以包含多个线程,每个线程共享进程的地址空间和系统资源。线程之间可以直接读写共享内存,因此线程间通信比进程间通信更加高效。

进程和线程的区别

image-20230604195427602

举一个现实的例子。我们可以想象一家餐厅。这个餐厅就像一个进程,有自己的独立空间和资源,比如桌子、椅子、炉灶和食材。而服务员则像线程,他们在餐厅中移动,完成不同的任务,比如点单、烹饪和送餐。

进程和线程的区别在于它们是如何使用资源的。就像餐厅中的进程一样,一个进程可以有自己的内存、文件和网络连接。而线程是进程中的小部分,它们共享进程的资源,但可以独立地执行任务。比如,在餐厅中,一个服务员可以独立地为一个桌子上的客人点单,而另一个服务员可以同时为另一个桌子上的客人点单。

  • 进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位)
  • 线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)

打开windows的任务管理器,就可以在这里看到进程一个列表,还可以看到每个进程的内存资源信息以及cpu占有率。

image-20230531090856284

浏览器的进程

浏览器是多进程的,浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu、内存)

简单点理解,每打开一个Tab页,就相当于创建了一个独立的浏览器进程

浏览器有自己的优化机制,有时候打开多个tab页后,可以在Chrome任务管理器中看到,有些进程会被合并

所以每一个Tab标签对应一个进程并不一定是绝对的,比如打开多个空白标签页后,会发现多个空白标签页被合并成了一个进程(Chrome的更多工具 -> 任务管理器)

早期浏览器的单进程结构及其问题

在早期,浏览器通常采用单进程结构,这意味着整个浏览器都运行在一个进程中。这个进程负责处理所有的标签页、插件和扩展。虽然这种结构很简单,但也存在一些问题

  • 用户经常会遇到浏览器崩溃的问题。

    因为如果是单进程,那么所有的标签页和插件都运行在同一个进程中,意味着一个标签页或插件崩溃了,整个浏览器就会崩溃。

  • 单进程结构会影响浏览器的性能和响应速度。

    如果一个标签页或插件需要大量的计算资源,它会占用整个进程的资源,导致其他标签页或插件反应迟缓。这也是早期浏览器经常被诟病的问题之一。

随着时间的推移,浏览器厂商采用了多进程结构来解决这些问题。

现代浏览器的多进程结构

现代浏览器通常采用多进程结构,每个标签页或扩展都运行在单独的进程中。这种结构可以提高浏览器的稳定性和安全性,同时也可以提高浏览器的性能和响应速度。

在多进程结构中,浏览器会分配一个主进程来管理所有的子进程。

  • 主进程(只有一个),负责处理浏览器的用户界面和一些核心功能,比如网络请求、文件系统访问和插件管理等。
  • 子进程(多个),每个标签页或插件扩展都有自己的独立进程,这些进程负责处理页面渲染、JavaScript 执行和插件运行等。

多进程优缺点

【优点】避免单个Tab页或第三方插件崩溃,影响整个浏览器

【缺点】内存等资源消耗会更大

Chrome浏览器主要包括如下进程

image-20230604155605224

浏览器进程(Browser Process)

也称为主进程,(负责协调、主控),只有一个。

主要作用:

  • 管理用户界面:浏览器进程负责管理用户界面,包括地址栏、书签栏、前进/后退按钮等。它还负责处理用户输入和响应用户请求。
  • 管理子进程:浏览器进程负责管理所有的子进程,包括渲染进程、插件进程和 GPU 进程等。它会为每个标签页创建一个独立的渲染进程,并在需要时创建其他进程。

渲染进程(Renderer Process)

负责将 HTML、CSS、JS 转换成网页,通常有多个

  • 每个标签页都有自己的渲染进程,当用户打开一个新的网页时,浏览器会创建一个新的渲染进程,并加载该网页的 HTML、CSS 和 JavaScript 等资源。一旦用户关闭了该网页,渲染进程也会被销毁。

  • 渲染进程会与浏览器进程通信,以获取用户设置、安全策略和其他信息。

  • 当满足某些条件如 tab 页超过一定数量或系统资源紧缺时会做合并优化(比如相同网站 tab 共用一个 渲染进程甚至不同网站 tab 共用一个渲染进程);

网络进程(NetWork Process)

主要负责页面的网络资源加载,通常只有1个。

主要作用

  • 处理网络请求:当你在浏览器中输入网址或进行其他网络操作时,网络进程会负责处理这些请求,并将其发送到服务器。它还负责处理 HTTPS 加密、Cookie、缓存等网络协议和机制。
  • 处理网络响应:当服务器返回响应时,网络进程会负责处理这些响应,并将其传递给渲染进程或其他进程。它还负责处理 HTTP 错误、网络超时等异常情况。
  • 处理网络安全:网络进程还负责处理浏览器的安全机制,包括 SSL/TLS 加密、证书验证、XSS 攻击和 CSRF 攻击等。

在早期的浏览器中,网络进程作为一个模块运行在浏览器进程里面,后面才独立出来,成为一个单独的进程

GPU 进程(GPU Process)

用于处理图形相关的任务,比如 3D 渲染和视频解码等。

插件进程(Plug-in Process)

负责在后台运行浏览器插件,有多个。

一些浏览器插件,比如 Flash、Java 和 Silverlight 等,需要运行在单独的进程中。这样可以防止插件崩溃影响到浏览器的其他部分。

实用程序进程(Utility Process)

它是现代浏览器中的一个特殊进程,用于处理一些特定的任务。

  • 处理浏览器的一些系统操作,比如下载、打印、截屏等。
  • 处理浏览器的一些内部通信,比如浏览器进程和渲染进程之间的通信。
  • 处理浏览器的一些系统资源,比如文件系统、存储和设备等。
  • 处理一些插件和扩展的特定任务,比如 Flash 视频播放和 PDF 阅读等。

其他进程

一些浏览器可能还会包括其他进程。

浏览器进程之间的协作

image-20230604162527810

浏览器各进程之间是通过 IPC(进程间通信) 来协作的,IPC可以实现数据的传递和同步。比如:

  • 当用户在地址栏输入URL时,浏览器进程会通过IPC将URL传递给网络进程,网络进程会发起HTTP请求,并将响应数据返回给浏览器进程。
  • 当浏览器进程收到响应数据后,会通过IPC将数据传递给渲染进程,渲染进程会解析数据并生成网页。
  • 当渲染进程需要绘制网页时,会通过IPC将绘制指令发送给GPU进程,GPU进程会调用GPU硬件进行绘制,并将结果显示在屏幕上。
  • 当渲染进程需要运行插件时,会通过IPC与插件进程进行通信,插件进程会执行插件的逻辑,并将结果返回给渲染进程。

渲染进程中的线程

对前端操作来说,最重要的就是渲染进程,页面的渲染,JS的执行,事件的循环,都在这个进程内进行。可以说渲染进程是浏览器中最重要的进程之一,所以下面详细说说渲染进程。

渲染进程中包含了多个线程,它们分别负责不同的功能和任务

image-20230604170637046

GUI线程(渲染界面)

负责渲染浏览器界面

  • 解析html和CSS、构建DOM树、CSSOM树、渲染树

  • 绘制页面,重绘(Repaint)回流(reflow)也是在该线程执行。

JS引擎线程(处理脚本)

也称为JS内核,负责处理Javascript脚本程序。

  • JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序。

如计算、逻辑判断、事件监听等,它使用了V8引擎作为执行环境。

事件触发线程

负责管理和调度页面中的事件。

  • 归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)
  • 当JS引擎执行代码块,如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中。
  • 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。
  • 由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)

为什么JavaScript是单线程的?

JavaScript之所以是单线程的,是因为它的设计者认为多线程会带来更多的问题。

比如, 如果Javascript是多线程的话,在多线程的交互下,假设存在两个线程同时操作一个DOM,一个负责修改一个负责删除,那么这个时候就需要浏览器来判断如何生效哪个线程的执行结果。很明显这会让编程变得更加困难,也容易出现各种问题和错误。与此相比,单线程的JavaScript更加简单和易于理解,也更容易维护和调试。

为了解决JavaScript单线程带来的性能问题,JavaScript也提供了异步编程机制,例如Promise和async/await等,以便更好地处理并发和异步操作。

定时器线程

负责执行页面中的定时器

  • setInterval与setTimeout所在线程
  • 浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)
  • 通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)
  • W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。

异步http请求线程

负责处理通过XMLHttpRequest对象发出Ajax请求

异步http请求线程是XMLHttpRequest连接后浏览器开的一个线程。

上面我们有说到网络进程,它是浏览器的一个单独进程,它负责处理所有的网络请求,包括http请求

当异步http请求线程发出一个Ajax请求时,它会将请求发送给网络进程,由网络进程去和服务器通信。当网络进程收到服务器的响应后,它会将响应结果返回给异步http请求线程。

如果有回调函数,异步http请求线程就会将回调函数放到事件队列中,等待JS引擎线程执行。

WebWorker线程(JS的多线程)

📖【了解】

负责执行页面中创建的WebWorker对象

当有大量计算时,有没有可能用多线程来解决呢,答案是可以。浏览器提供了Web Workers API来解决这个问题。

  • 创建Worker时,JS引擎向浏览器申请开一个子线程(子线程是浏览器开的,完全受主线程控制,而且不能操作DOM)
  • JS引擎线程与worker线程间通过特定的方式通信(postMessage API,需要通过序列化对象来与线程交互特定的数据)

WebWorker是一种可以在后台运行的JavaScript代码,它可以实现多线程编程,提高页面性能。(Worker可以理解是浏览器给JS引擎开的外挂,专门用来解决那些大量计算问题。)

WebWorker与SharedWorker

📖【拓展】

Web Worker 是一种单向通信的多线程机制而Shared Worker 则是一种双向通信的多线程机制。

  • WebWorker只属于某个页面,不会和其他页面的Render进程(浏览器内核进程)共享

    所以Chrome在Render进程中(每一个Tab页就是一个render进程)创建一个新的线程来运行Worker中的JavaScript程序。

  • SharedWorker是浏览器所有页面共享的,不能采用与Worker同样的方式实现,因为它不隶属于某个Render进程,可以为多个Render进程共享使用

    所以Chrome浏览器为SharedWorker单独创建一个进程来运行JavaScript程序,在浏览器中每个相同的JavaScript只存在一个SharedWorker进程,不管它被创建多少次

    本质上就是进程和线程的区别。SharedWorker由独立的进程管理,WebWorker只是属于render进程下的一个线程。

线程之间的关系

这些线程之间既有协作关系,又有互斥关系。例如

互斥

GUI线程和JS引擎线程是互斥的

也就是说当JS引擎线程在执行JavaScript代码时,GUI线程会被挂起,不能绘制页面或响应用户操作,反之亦然。这就导致了页面可能出现卡顿或假死的现象。

为什么它们要是互斥的关系呢?

因为JavaScript是可操纵DOM的,如果在修改这些元素属性同时渲染界面(即GUI线程和JS引擎线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。

性能优化?

所以因为这个互斥关系,要尽量避免JS执行时间过长,否则就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

协作

事件触发线程和定时器线程是协作的

也就是说它们都会将回调函数放入事件队列中,并通知JS引擎线程执行。但是事件队列是先进先出(FIFO)的,也就是说先放入队列的回调函数会先被执行,后放入队列的回调函数会后被执行。这就导致了定时器可能不准确或延迟的现象。

对Web开发的意义

浏览器的进程和线程对Web开发有很大的影响和意义,因为它们决定了浏览器的性能、稳定性、安全性和兼容性等方面。作为Web开发者,我们需要了解浏览器的内部工作原理,以便更好地设计和优化我们的Web应用程序。


参考资料:

Chromium 如何显示网页

Inside look at modern web browser

浏览器多进程

🎨【点赞】【关注】不迷路,更多前端干货等你解锁

往期推荐

👉 Vite基础入门

👉 15 个JavaScript数组实用技巧

👉 JavaScript数组方法看这一篇就够了

👉 JS内置日期对象Date的使用指南