一、基本概念:
浏览器是多进程的
浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu、内存)
简单点理解,每打开一个Tab页,就相当于创建了一个独立的浏览器进程。
二、浏览器都包含哪些进程?
1. Browser进程:浏览器的主进程(负责协调、主控),只有一个。作用有
负责浏览器界面显示,与用户交互。如前进,后退等
负责各个页面的管理,创建和销毁其他进程
将Renderer进程得到的内存中的Bitmap,绘制到用户界面上
网络资源的管理,下载等
2. 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
3. GPU进程:最多一个,用于3D绘制等
4. 浏览器渲染进程(浏览器内核)(Renderer进程,内部是多线程的):默认每个Tab页面一个进
程,互不影响。主要作用是页面渲染,脚本执行,事件处理等
三、浏览器多进程的优势有哪些?
相比于单进程浏览器,多进程有如下优点:
避免单个page crash影响整个浏览器
避免第三方插件crash影响整个浏览器
多进程充分利用多核优势
方便使用沙盒模型隔离插件等进程,提高浏览器稳定性
四、浏览器内核(渲染进程)
页面的渲染,JS的执行,事件的循环,都在这个进程内进行,浏览器的渲染进程是多线程的
1. GUI渲染线程
负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。
当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行
注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻
结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
2. JS引擎线程
也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)
JS引擎线程负责解析Javascript脚本,运行代码。
JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无
论什么时候都只有一个JS线程在运行JS程序。
同样注意,GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成
页面的渲染不连贯,导致页面渲染加载阻塞。
3. 事件触发线程
归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏
览器另开线程协助)
当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX
异步请求等),会将对应任务添加到事件线程中
当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引
擎的处理
注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引
擎空闲时才会去执行)
4. 定时触发器线程
传说中的 setInterval 与 setTimeout 所在线程
浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处
于阻塞线程状态就会影响记计时的准确)
通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执
行)
注意,W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。 5. 异步http请求线程
XMLHttpRequest在连接后是通过浏览器新开一个线程请求
将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再
放入事件队列中。再由JavaScript引擎执行。
五、Browser进程和浏览器内核(Renderer进程)的通信过程
Browser进程收到用户请求,首先需要获取页面内容(譬如通过网络下载资源),随后将该任务通
过RendererHost接口传递给Render进程
Renderer进程的RendererHost接口收到消息,简单解释后,交给渲染线程,然后开始渲染
渲染线程接收请求,加载网页并渲染网页,这其中可能需要Browser进程获取资源和需要
GPU进程来帮助渲染
当然可能会有JS线程操作DOM(这样可能会造成回流并重绘)
最后Render进程将结果传递给Browser进程
Browser进程接收到结果并将结果绘制出
六、理浏览器内核中线程之间的关系
1.GUI渲染线程与JS引擎线程互斥
由于JavaScript是可操纵DOM的,如果在修改这些元素属性同时渲染界面(即JS线程和UI线程同时运
行),那么渲染线程前后获得的元素数据就可能不一致了。
因此为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程与JS引擎为互斥的关系,当JS引擎执
行时GUI线程会被挂起, GUI更新则会被保存在一个队列中等到JS引擎线程空闲时立即被执行。
2.JS阻塞页面加载
从上述的互斥关系,可以推导出,JS如果执行时间过长就会阻塞页面。
譬如,假设JS引擎正在进行巨量的计算,此时就算GUI有更新,也会被保存到队列中,等待JS引擎空闲
后执行。 然后,由于巨量计算,所以JS引擎很可能很久很久后才能空闲,自然会感觉到巨卡无比。
所以,要尽量避免JS执行时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。