浏览器是多进程的总结:最后,下面可能有多个渲染进程(每个标签页浏览器都会启动一个渲染进程)浏览器进程:浏览器的只有一个主进程(负责协调和主控)。负责显示浏览器界面并与用户进行交互。如forward、back等负责管理各个页面,创建和销毁其他进程,将Renderer进程获得的内存中的Bitmap绘制到用户界面,管理网络资源,下载第三方插件等-inprocesses:每种插件对应一个Process,仅当插件用于创建GPU进程时:最多一个,用于3D绘图等浏览器渲染进程(浏览器内核)(Rendererprocess,internallymulti-threaded:默认情况下,每个Tab页都会生成一个渲染进程,相互独立。主要功能是页面渲染、脚本执行、事件处理等。如何查看浏览器进程打开ChromeShift+Esc;我们可以看到进程,Chrome图标是浏览器的主进程多线程优缺点避免单个页面崩溃影响整个浏览器避免第三方插件崩溃影响整个浏览器多进程。充分利用多核的优势。方便使用沙箱模型隔离插件和其他进程,提高浏览器的稳定性。简单理解:如果浏览器是单进程,那么一个标签页崩溃,会影响到如果是单进程,插件的崩溃也会影响到整个浏览器;而多进程还有很多其他优点,当然内存等资源消耗会更大。重点是浏览器Kernel(渲染进程),这个进程有多个线程来完成GUI渲染。该线程负责渲染浏览器界面,解析HTML、CSS,构建DOM树和RenderObject树,布局绘制等。当界面需要重绘(Repaint)或由于某些操作引起回流(reflow)时,threadwillbeexecuted注意GUI渲染线程和JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结),GUI更新会保存在一个队列中并立即执行当JS引擎空闲时。为什么互斥:既然JS可以操作DOM,如果同时修改元素属性和渲染界面(即JS线程和UI线程同时运行),那么前后获取的元素渲染线程可能不一致(简单来说js修改dom后没有重新渲染成功)JS引擎线程又称为JS内核,负责处理Javascript脚本程序。(如V8引擎)JS引擎线程负责解析Javascript脚本并运行代码。JS引擎一直在等待任务队列中任务的到来,然后进行处理。任何时候一个Tab页(renderer进程)中只有一个JS线程在运行JS程序。还要注意GUI渲染线程和JS引擎线程是互斥的,所以如果JS的执行时间过长,就会导致页面渲染不连贯,导致页面渲染加载受阻。事件触发线程属于浏览器而非JS引擎,用于控制事件循环(JS引擎本身忙不过来,需要浏览器另开线程辅助,无可厚非)。当JS引擎执行setTimeOut等代码块时(或者来自浏览器内核中的其他线程,比如鼠标点击、AJAX异步请求等),会在事件线程中添加相应的任务。当对应的事件满足触发条件被触发时,线程会将事件添加到pendingqueue的尾部,等待JS引擎的处理。注意,由于JS的单线程关系,这些待处理队列中的事件必须排队等候JS引擎处理(仅当JS引擎空闲时)。传说中的setInterval和setTimeout(这些API不是引擎提供的而是浏览器提供的WebAPI,如DOM、AJAX、setTimeout)其中线程浏览器计时计数器是JavaScript引擎不统计的,(因为JavaScript引擎是单线程的,如果处于阻塞线程状态会影响计时精度)因此使用单独的线程来计时和触发计时(计时完成后加入事件队列,在JS之后执行发动机怠速)。注意,W3C在HTML标准中规定,setTimeout中要求Intervals低于4ms算作4ms。当异步http请求线程在连接XMLHttpRequest后通过浏览器开启新的线程请求检测到状态变化时,如果设置了回调函数,异步线程会产生一个状态变化事件,并将回调放入事件队列中。然后由JavaScript引擎执行。进程间通信过程当Browser进程收到用户请求时,首先需要获取页面内容(如通过网络下载资源),然后通过RendererHost接口将任务传递给Render进程。Renderer进程的Renderer接口收到消息,经过简单的解释后,发送给渲染线程,然后开始渲染。渲染线程接收到请求,加载网页并渲染网页,这可能需要Browser进程获取资源,GPU进程帮助渲染。当然也可能有JS线程去操作DOM(这可能会造成回流和重绘)最后Render进程将结果传递给Browser进程。Browser进程接收结果并绘制结果。渲染进程(浏览器内核)线程之间的关系。GUI渲染线程和JS引擎线程是互斥的。由于JavaScript可以操作DOM,如果修改这些Element属性同时渲染界面(即JS线程和UI线程同时运行),那么渲染线程前后获取的元素数据可能不一致。所以,为了防止渲染结果不可预知,浏览器将GUI渲染线程和JS引擎设置为互斥。当JS引擎执行时,GUI线程会被挂起,GUI更新会保存在一个队列中,等到JS引擎线程空闲时立即执行。JS阻塞页面加载从上面的互斥关系可以推导出,如果JS执行时间过长,就会阻塞页面。比如,假设JS引擎正在做巨大的计算,即使此时更新了GUI,也会保存在队列中,待JS引擎空闲后再执行。那么,由于计算量巨大,JS引擎很可能长期处于闲置状态,自然会觉得巨卡无比。因此,尽量避免JS执行时间过长,导致页面渲染不连贯,造成页面渲染加载阻塞的感觉。WebWorker,JS的多线程JavaScript引擎在单线程中运行,将JavaScript中耗时的I/O操作作为异步操作处理,包括键盘、鼠标I/O输入输出事件、窗口大小resize事件、timers(setTimeout,setInterval)事件,Ajax请求网络I/O回调等。当这些异步任务发生时,会被放入浏览器的事件任务队列中,按照先进先出的顺序依次执行-outJavaScript运行时执行线程空闲时队列的原理,但毕竟还是单线程的。.创建Worker时,JS引擎向浏览器申请开启一个子线程(子线程由浏览器开启,完全由主线程控制,不能操作DOM)。JS引擎线程以特定方式与工作线程通信(postMessageAPI,需要序列化对象才能与线程专有数据交互)//主线程main.jsvarworker=newWorker("worker.js");worker.onmessage=function(event){//主线程从子线程接收消息Message};//主线程向子线程发送消息worker.postMessage({type:"start",value:12345});//webworker.jsonmessage=function(event){//收到};postMessage({type:"debug",message:"Startingprocessing..."});浏览器渲染进程获取内容。浏览器从DNS服务器获取域名的IP地址,并向拥有该IP的机器发送HTTP请求。服务器接收、处理并返回HTTP请求浏览器获取返回内容,解析内容,构建RenderingTree,解析HTMl,构建domdom功能:HTMLDOM是HTMLDocumentObjectModel(文档对象模型)的缩写,HTMLDOM是一种特别适用于HTML/XHTML的文档对象模型。熟悉软件开发的人可以将HTMLDOM理解为网页的API。它将网页中的每一个元素都看作一个对象,使得网页中的元素也可以通过计算机语言获取或编辑。dom规定整个文档是一个文档节点,每个HTML标签是一个元素节点,HTML元素包含的文本是一个文本节点,每个HTML属性是一个属性节点(属性节点是另外一个层次的理解,打印在浏览器后台时,没有属性节点)评论属于评论节点解析过程:浏览器会自动将HTML文档解析成一个“DocumentObjectModel”,即DocumentObjectModel,DOM为简而言之,这是一个树结构,树的根是Document对象,树干是网页的根元素,然后分出两个分支,一个是
,一个是,然后网页上的其他标签就是这棵树的叶子和树枝。通过这个结构,你可以找到和控制网页上的任何元素。因此,可以说网页上的任何元素都是Document对象的子对象。解析CSS生成CSS规则树。CSS由一个单独的下载线程异步下载。它不会阻止Dom加载。它更类似于DOM结构,然后结合DOM生成RenderTreeJavascript解析。通过DOMAPI和CSSOMAPIRuleTree操作DOMTree和CSS。布局渲染树(Layout/reflow),负责计算每个元素的大小和位置绘制渲染树(paint),绘制页面像素信息浏览器会将每一层的信息发送给GPU,由GPU合成每一层(复合),渲染过程中屏幕显示的问题页面上已经加载完成。(渲染完成)DOMContentLoaded->load浏览器渲染时遇到JS文件怎么办?上面说了,GUI渲染线程和JS引擎线程是互斥的,所以在渲染过程中,如果遇到没有defer或async,浏览器会立即加载并执行指定的脚本,也就是说不要等待文档元素稍后加载,读取时加载并执行它。(延迟执行)defer属性表示引入的JavaScript延迟执行,即加载这段JavaScript时HTML不停止解析,两个过程是平行的。在解析完整个文档并加载defer-script之后(这两件事的顺序无关紧要),将执行defer-script加载的所有JavaScript代码,然后触发DOMContentLoaded事件。defer与普通脚本相比有两个不同:加载JavaScript文件时不阻塞HTML解析,执行阶段放在HTML标签解析完成之后。(异步下载)后续文档元素的加载和渲染过程将与script.js的加载和执行并行(异步)执行。async属性表示异步执行引入的JavaScriptdefer和async。综上所述,defer和async在网络读取(下载)上是一样的,都是异步的(相对于HTML解析)。defer的script.js的执行必须在所有元素解析完成后,如果已经加载了async,才会开始执行。即加载不被阻塞,但是执行被阻塞。加载多个JS脚本时,async是乱序加载的,而defer是顺序加载的。async对于应用程序脚本不是很有用,因为它根本不考虑依赖关系(即使是最低阶执行),但它非常适合不能依赖或被任何脚本依赖的脚本