浏览器多进程与js单线程
pr1mavera 2019/11/28
进程 & 线程
# 整体概念
# 对比工厂和工人
- 类似于一个工厂,有自己独立的资源(系统为进程分配的独立内存)
- 工厂之间相互独立(进程之间相互独立)
- 工厂中有一个或多个工人(进程管理一个或多个线程程)
- 多个工人协作完成任务(进程中的线程互相协作)
- 工人之间共享工厂资源(同一进程下的各个线程之间共享程序的内存空间:包括代码段、数据集、堆等)
# 官方一些的描述
- 进程
- 是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位)
- 不同进程之间可以通信,代价较大
- 浏览器每打开一个 tab 页,就相当于创建了一个独立的浏览器进程(浏览器有自己的优化机制,某些契机下会合并进程)
- 线程
- 是cpu调度的最小单位
- 是建立在进程的基础上的一次程序运行单位
- 一个进程中可以有多个线程
- 线程之间各司其职、互相协作,共同完成一个进程中的工作
# 浏览器多进程
# 包含的主要进程
浏览器中包含的主要进程:
- 浏览器主进程
- 第三方插件进程
- GPU进程
- 渲染进程(浏览器内核)
可以打开 Chrome 的 更多工具
-> 任务管理器
查看
# 浏览器主进程(唯一)
- 浏览器中起管理作用:
- 界面显示、用户交互(前进,后退等)的管理
- 各页面进程的管理
- 其他进程创建和销毁的管理
- 网络资源的管理与下载
- 与渲染相关的作用:
- 将渲染进程(内核)得到的内存中的 Bitmap ,绘制到用户界面
# 第三方插件进程
- 每种类型的插件对应一个进程
- 仅当使用该插件时才创建
# GPU进程(唯一)
- 用于3D绘制等
# 渲染进程(每个tab页一个)
- 又称为 浏览器内核
- 流行的浏览器内核
- WebKit - 原Chrome、Safari
- Blink - Chrome
- Gecko - Firefox
- Trident - IE(不开源)
- 每个渲染进程之间互不影响
- 主要作用:
- 页面渲染
- 脚本执行
- 事件处理
# 浏览器多进程的优势
- 避免单个页面、插件崩溃导致浏览器崩溃
- 多进程充分利用多核优势
- 方便使用沙盒模型隔离插件等进程,提高浏览器稳定性
# 渲染进程中包含的常驻线程
一个浏览器渲染进程中包含的常驻线程:
- 界面渲染线程
- JS引擎线程
- 事件触发线程(异步任务队列)
- 定时触发器线程
- 异步http请求线程
# 界面渲染线程
- 负责浏览器界面渲染,解析 HTML 构建DOM树,解析 CSS 构建CSSOM树 等
- 重绘(Repaint)、回流(reflow)
- 与 JS引擎线程 互斥,JS引擎线程有任务执行时,界面渲染线程将被挂起(GUI更新会被保存在一个队列中),等到JS引擎线程空闲时立即执行执行
- 互斥的原因:JS引擎执行的脚本有可能修改UI界面,界面渲染与脚本执行同时进行时可能导致渲染出错
# JS引擎线程
- 又叫 js内核(一个进程中唯一)
- js单线程:一个渲染进程中唯一存在一个JS引擎线程
- 流行的js引擎
- SpiderMonkey(Mozilla) - 第一款JavaScript引擎
- TraceMonkey(Mozilla) - 基于实时编译的引擎
- V8(Google) - Chrome、NodeJS使用的js引擎
- KJS(Konqueror) - KDE的ECMAScript/JavaScript引擎
- 负责处理Javascript脚本程序
- JS引擎的表现形式:循环查看当前队列中是否存在事件需要执行,当JS引擎线程闲置时,会去事件触发线程查看是否存在异步事件,有则拉取过来作为一次循环再次执行
- JS引擎的一次循环被称为一次宏任务执行
- 与 界面渲染线程 互斥,JS引擎线程 将阻塞 界面渲染线程
# 事件触发线程(异步任务队列)
- 归属于浏览器
- 控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)
- 引擎读取到的异步(setTimeout)、事件脚本(click),会将对应任务添加到事件线程中
- 当保存的任务符合条件触发时,事件触发线程会将事件添加到 -> 待处理队列的队尾,等待JS引擎线程空闲时处理
# 定时触发器线程
setInterval
与setTimeout
所在线程- 通过单独线程来计时并触发定时
- 当触发定时器时,定时触发器线程会将事件添加到 -> 事件触发线程的待处理队列的队尾,等待JS引擎线程空闲时处理
- tip: W3C标准中规定:要求setTimeout中低于4ms的时间间隔算为4ms
# 异步http请求线程
- 在 XMLHttpRequest 在连接后是通过浏览器新开一个线程请求
- 将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调添加到 -> 事件触发线程的待处理队列的队尾,等待JS引擎线程空闲时处理
# 浏览器主进程与渲染进程的通信
打开一个浏览器的线程通信:
- 浏览器主进程收到用户请求,首先需要获取页面内容(譬如通过网络下载资源),随后将该任务通过RendererHost接口传递给界面渲染进程
- 界面渲染进程的Renderer接口收到消息,简单解释后,交给渲染线程,然后开始渲染
- 渲染线程经由界面渲染进程帮助计算元素位置、排列、绘制,得到结果(Bitmap)
- 浏览器主进程收到结果(Bitmap)将其渲染出来