简介
- 进程是CPU资源分配的最小单位。是能拥有资源和独立运行的最小单位,不同进程之间不会共享资源。
- 线程是CPU调度的最小单位。一个进程中可以有多个线程,多个线程之间共享进程的资源。
- 不同进程之间也能通信,但是代价较大。
用公司和员工来做比喻,进程代表公司,线程代表员工:
- 不同公司(进程)之间,不会共享资产/资源(办公用品、内部系统、客户信息等)
- 一个公司中可以有多个员工,员工是没有自己的资源和空间的,但是他们可以使用和共享公司的资源和空间
- 每个公司(进程)之间可以交流(通信),但是代价较大
浏览器中的进程
- 浏览器是多进程的
- 浏览器每多开一个
tab
,都相当于系统为其创建了一个独立的进程 - 浏览器之所以能够运行,是因为系统为其进程分配了资源
进程之间是相互独立的,线程是资源共享的:
有时我们会发现浏览器的某个 tab
挂了,但是其他 tab
可以正常运行,这就很好的说明了每个 tab
都是一个独立的进程。因为如果 tab
是线程的话,一个线程挂了,其他线程也会受到影响。
1、浏览器(Browser)进程
浏览器的主进程(只有一个),负责协调、主控。
- 负责浏览器的界面显示,用户交互,网址输入、前进、后退等。
- 负责各个页面的创建和销毁。
- 将页面内容写入到浏览器内存中,最后将图像显示在屏幕上。
- 文件存储等功能
Browser进程中的线程:
- UI线程:该线程是程序运行的主线程,是程序的入口点,用来处理用户交互(如监听用户输入、前进后退等)。同时,会分发任务给其他相应线程去执行。
- IO线程:处理
Browser
进程与其他进程进行进程间通信,下载Renderer
进程所需的资源文件等。 - File线程:读取磁盘文件,下载文件到磁盘等。
- 数据库线程:进行一些数据库操作,例如保存
Cookie
到数据库 - 历史记录线程
- http服务代理线程
2、渲染(Renderer)进程
渲染进程内部是多线程的。
默认情况下,一个 tab
配一个渲染进程。主要的作用是页面渲染、脚本执行、事件处理等。
Renderer进程中的线程:
- GUI渲染线程
- JavaScript引擎线程
- 事件触发线程
- 定时器线程
- 异步http请求线程
3、GPU进程
用于3D绘制,将开启了3D绘制的元素渲染由CPU转向GPU,最多一个。
也就是GPU加速。
4、网络进程
主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程中,现在独立出来,成为一个单独的进程。
5、插件进程
每种类型的插件对应一个进程,仅当使用该插件是才创建。
6、音频进程
浏览器的音频管理。
Browser进程与Renderer进程间的通信
以开启一个新 tab
为例
Browser进程
中的UI线程处理用户交互,接收到用户请求,转交给IO线程Browser进程
中的IO线程获取页面内容(通过网络请求或本地缓存),随后将该任务通过RendererHost
接口传递给Renderer
进程Renderer进程
的Renderer接口
收到消息,简单解释后交给渲染线程,进行html
、css
解析,渲染页面,js
执行等任务Renderer
进程将得到的结果传递给Browser
进程Browser进程
接收到结果并在界面上绘制出图像
优势
相较于单进程而言,多进程的优势:
- 避免单个页面奔溃影响整个浏览器
- 避免第三方插件奔溃影响整个浏览器
- 多进程可以充分利用多核优势
- 方便使用沙盒模型隔离插件等进程,提高浏览器的稳定性
空间换时间
浏览器的线程(这里都是Renderer进程中的线程)
页面的渲染是多线程的;JS是单线程(会阻塞)的
常用的线程有 JS引擎线程、HTTP请求线程、定时触发线程、事件处理线程、GUI渲染线程
1、JS引擎线程
- 也称为JS内核,负责处理
JavaScript
脚本程序。(例如V8引擎)。 - JS引擎线程负责解析
JavaScript
脚本,然后运行代码。 - JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个
Tab页
(render进程)中无论什么时候都只有一个 JS线程 在运行JS程序。 - GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。
2、HTTP请求线程
XMLHttpRequest
在连接后会通过浏览器新开一个线程来进行请求(异步)。- 检测到状态变更时,如果设置有回调函数,异步线程就会产生状态变更事件,将这个回调放入事件队列中。再交由
JavaScript引擎
执行。
3、定时触发器线程
setTimeout` 和 `setInterval
- 浏览器的定时器并不是由
JavaScript引擎
来计数的。(因为JavaScript引擎
是单线程的,如果处于阻塞线程状态的话就会影响计时器的准确性) - 因此通过单线程来计时并触发定时。(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)
注意:在 W3C的HTML标准中规定,要求
setTimeout
中低于 4ms 的时间间隔算作 4ms。
4、事件处理线程
事件处理线程归属于浏览器而不是JS引擎,用来控制事件循环。(JS引擎自己都忙不过来,需要浏览器另外开辟线程来协助处理)。
当JS引擎执行代码时(如果其中有异步、鼠标点击事件等),会将对应任务添加到事件现场中。
当对应的事件符合条件并被触发时,事件处理线程会把事件添加到待处理队列的尾部,等待JS引擎的处理。
注意:由于JS是单线程的原因,所以这些待处理队列中的事件都是排队等待JS引擎处理(等到JS引擎空闲的时候再去执行)
5、GUI渲染线程
GUI渲染线程:负责渲染浏览器界面,解析HTML、CSS,构建DOM树和 Render 树,进行布局和绘制等。
触发执行:当页面需要重绘或由于某种操作引发回流(重排)时,GUI渲染线程就会触发。
注意:GUI渲染线程与JS引擎是互斥的,当JS引擎执行时,GUI线程会被挂起,GUI更新会被保存在一个队列中直到JS引擎空闲时才会继续执行。
总结
- 浏览器是多进程的
- JS执行的主线程为JS引擎,并且无论何时都只有一个JS线程在执行,所以是单线程的。
- GUI渲染线程和JS引擎线程是互斥的,JS会阻塞页面的加载和渲染
- 定时器(
setTimeout
、setInterval
)会在定时触发线程中进行计时 - 定时触发线程计时结束后需要执行的事件和异步HTTP请求线程的回调事件都会进入到事件触发线程的任务队列中等待JS引擎的执行。