浏览器的多进程包括:
1.Browser进程:浏览器的主进程(负责协调、主控),只有一个
2.第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
3.GPU进程:最多一个,用于3D绘制等
4.浏览器渲染进程(浏览器内核内部是多线程的):默认每个Tab页面一个进程,互不影响。
浏览器渲染进程包括:
GUI渲染线程JS引擎线程事件触发线程定时器触发线程异步http请求线程GUI渲染线程:负责浏览器渲染,重排重绘。
注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
渲染完毕后会触发load事件:
DOMContentLoaded(仅当DOM加载完成,不包括样式表,图片) -> onload(页面上所有的DOM,样式表,脚本,图片都已加载完成)
css是由单独的下载线程异步下载的,css加载不会阻塞DOM树解析(异步加载时DOM照常构建)
但会阻塞render树渲染(渲染时需等css加载完毕,因为render树需要css信息)
JS引擎线程:负责处理Javascript脚本程序。是主线程,一直等待着任务队列中任务的到来。
js是单线程处理,执行时间过长会阻塞页面,所以HTML5中支持了Web Worker。
这样理解下:
创建Worker时,JS引擎向浏览器申请开一个子线程(子线程是浏览器开的,完全受主线程控制,而且不能操作DOM)JS引擎线程与worker线程间通过特定的方式通信(postMessage API,需要通过序列化对象来与线程交互特定的数据)
JS引擎是单线程的,这一点的本质仍然未改变,Worker可以理解是浏览器给JS引擎开的外挂,专门用来解决那些大量计算问题。
事件触发线程:归属于浏览器而不是JS引擎,用来控制事件循环。维护一个任务队列,当使用setTimeout或setInterval时,需要定时器触发线程计时,计时完成后才将其回调函数加入任务队列。
当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)
定时器触发线程:setInterval与setTimeout所在线程
浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)
补充:
WebWorker与SharedWorker
WebWorker只属于某个页面,不会和其他页面的Render进程(浏览器内核进程)共享所以Chrome在Render进程中(每一个Tab页就是一个render进程)创建一个新的线程来运行Worker中的JavaScript程序。SharedWorker是浏览器所有页面共享的,不能采用与Worker同样的方式实现,因为它不隶属于某个Render进程,可以为多个Render进程共享使用。所以Chrome浏览器为SharedWorker单独创建一个进程来运行JavaScript程序,在浏览器中每个相同的JavaScript只存在一个SharedWorker进程,不管它被创建多少次。
看到这里,应该就很容易明白了,本质上就是进程和线程的区别。SharedWorker由独立的进程管理,WebWorker只是属于render进程下的一个线程
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.