CPU、进程、线程之间的关系
进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位)线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)- 不同
进程之间也可以通信,不过代价较大 单线程与多线程,都是指在一个进程内的单和多
浏览器是多进程的
对于计算机来说,每一个应用程序都是一个进程, 而每一个应用程序都会分别有很多的功能模块,这些功能模块实际上是通过子进程来实现的。 对于这种子进程的扩展方式,我们可以称这个应用程序是多进程的。
浏览器就是多进程的,主要有:
-
主进程
- 协调控制其他子进程(创建、销毁)
- 浏览器界面显示,用户交互,前进、后退、收藏
- 将渲染进程得到的内存中的Bitmap,绘制到用户界面上
- 处理不可见操作,网络请求,文件访问等
-
第三方插件进程
- 每种类型的插件对应一个进程,仅当使用该插件时才创建
-
GPU进程
- 用于3D绘制等
-
渲染进程,就是我们说的浏览器内核- 负责页面渲染,脚本执行,事件处理等
- 每个tab页一个渲染进程
那么浏览器中包含了这么多的进程,那么对于普通的前端操作来说,最重要的是什么呢?
答案是渲染进程,也就是我们常说的浏览器内核
渲染进程是多线程的
一个渲染进程包含:
-
主线程- 调度其他
-
GUI渲染线程- 负责渲染页面,布局和绘制
- 页面需要重绘和回流时,该线程就会执行
- 与
js引擎线程互斥,防止渲染结果不可预期
-
JS引擎线程- 负责处理解析和执行javascript脚本程序
- 只有一个JS引擎线程(单线程)
- 与
GUI渲染线程互斥,防止渲染结果不可预期
-
事件触发线程- 用来控制事件循环(鼠标点击、setTimeout、ajax等)
- 当事件满足触发条件时,将事件放入到JS引擎所在的执行队列中
-
定时触发器线程- setInterval与setTimeout所在的线程
- 定时任务并不是由JS引擎计时的,是由定时触发线程来计时的
- 计时完毕后,通知事件触发线程
-
异步http请求线程- 浏览器有一个单独的线程用于处理AJAX请求
- 当请求完成时,若有回调函数,通知事件触发线程
-
io线程- 用来接收其他进程的消息
为什么 GUI 渲染线程与 JS 引擎线程互斥? 这是由于 JS 是可以操作 DOM 的,如果同时修改元素属性并同时渲染界面(即
JS线程和UI线程同时运行), 那么渲染线程前后获得的元素就可能不一致了。 因此,为了防止渲染出现不可预期的结果,浏览器设定GUI渲染线程和JS引擎线程为互斥关系, 当JS引擎线程执行时GUI渲染线程会被挂起,GUI更新则会被保存在一个队列中等待JS引擎线程空闲时立即被执行。
每个渲染进程都有一个主线程,并且主线程非常繁忙,既要处理 DOM,又要计算样式,还要处理布局,同时还需要处理 JavaScript 任务以及各种输入事件。要让这么多不同类型的任务在主线程中有条不紊地执行,这就需要一个系统来统筹调度这些任务,这个统筹调度系统就是消息队列和事件循环
eventLoop
- 很多事情都是在主线程做的,例如:js代码执行,页面布局计算,渲染等
- 主线程同一时刻只能做一件事,事情多了就要排队。所以主线程维护了任务队列。
- 某个事件发生时,事件触发线程 就把对应的任务添加到主线程的任务队列中。
- 主线程上的任务完成之后,就会从任务队列中取出任务来执行。
事件发生时,将其回调添加到任务队列;主线程上的任务完成之后,就会从任务队列中取出任务来执行,此过程不断重复从而形成一个循环,称为eventLoop。
setTimeout
定时触发器线程会在指定时间之后,将其回调添加到主线程的任务队列
微任务
通常我们把消息队列中的任务称为宏任务,每个宏任务中都包含了一个微任务队列,在执行宏任务的过程中,如果有优先级更高的任务,添加到微任务列表中,这样就不会影响到宏任务的继续执行,也就解决了执行效率的问题。
等宏任务中的主要功能都直接完成之后,这时候,渲染引擎并不着急去执行下一个宏任务,而是执行当前宏任务中的微任务,这样也就解决了实时性问题。
总之,它能控制任务执行的优先级。