浏览器分为如下7个部分:javascript
不一样的浏览器有不一样的呈现引擎,例如:
Chrome: Blink。Blink是Webkit的一个分支,添加了一些优化新特性。
Safari: Webkit
Firfox: Gecko
IE: Trident
一样不一样的浏览器有不一样的JS解释器,例如:
Chrome: V8引擎。以前是机器码,最近重回字典码
Safari: JavaScriptCore引擎
Firfox: Ion引擎
PS:不一样浏览器间引擎性能差距不大,详见 https://arewefastyet.com
2018年2月份占比html
浏览器渲染引擎最重要的工做就是将 HTML 和 CSS 文档解析组合最终渲染到浏览器窗口上。以下图所示:前端
解析 HTML 构建 DOM 树时渲染引擎会将 HTML 文件的便签元素解析成多个 DOM 元素对象节点,而且将这些节点根据父子关系组成一个树结构。同时 CSS 文件被解析成 CSS 规则表,而后将每条 CSS 规则按照「从右向左」的方式在 DOM 树上进行逆向匹配,生成一个具备样式规则描述的 DOM 渲染树。接下来就是将渲染树进行布局、绘制的过程。首先根据 DOM 渲染树上的样式规则,对 DOM 元素进行大小和位置的定位,关键属性如position;width;margin;padding;top;border;...,接下来再根据元素样式规则中的color;background;shadow;...规则进行绘制。另外,这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽量早的将内容呈现到屏幕上,并不会等到全部的 html 都解析完成以后再去构建和布局 render 树。它是解析完一部份内容就显示一部份内容,同时,可能还在经过网络下载其他内容。java
再者,须要注意的是,在浏览器渲染完首屏页面后,若是对 DOM 进行操做会引发浏览器引擎对 DOM 渲染树的从新布局和从新绘制,咱们叫作「重排」和「重绘」,因为重排和重绘是先后依赖的关系,重绘发生时未必会触发渲染引擎的重排,可是若是发生了重排就必然会触发重绘操做,这样带来的性能损害就是巨大的。所以咱们在作性能优化的时候应该遵循「避免重排;减小重绘」的原则。[1]git
在浏览器刚被设计出来的时候,那时的网页很是的简单,每一个网页的资源占有率是很是低的,所以一个进程处理多个网页时可行的。而后在今天,大量网页变得日益复杂。把全部网页都放进一个进程的浏览器面临在健壮性,响应速度,安全性方面的挑战。由于若是浏览器中的一个tab网页崩溃的话,将会致使其余被打开的网页应用。另外相对于线程,进程之间是不共享资源和地址空间的,因此不会存在太多的安全问题,而因为多个线程共享着相同的地址空间和资源,因此会存在线程之间有可能会恶意修改或者获取非受权数据等复杂的安全问题。
所以Chrome浏览器针对每个tab页签,都开了一个进程。github
浏览器的内核是多线程的,它们在内核控制下相互配合以保持同步,一个浏览器大概会有如下几个线程:JavaScript引擎线程,GUI渲染线程(又称为UI主线程),浏览器事件触发线程,异步 HTTP 请求线程(Chrome最多并发6个)。web
JavaScript引擎是基于事件驱动单线程执行的,JavaScript引擎一直等待着任务队列中任务的到来,而后加以处理,浏览器不管何时都只有一个JavaScript线程在运行JavaScript程序。segmentfault
var isEnd = true; window.setTimeout(function () { isEnd = false;//1s后,改变isEnd的值 }, 1000); //这个while永远的占用了js线程,因此setTimeout里面的函数永远不会执行 while (isEnd);
GUI渲染线程负责渲染浏览器界面,当界面须要重绘(Repaint)或因为某种操做引起回流(Reflow)时,该线程就会执行。但须要注意,GUI渲染线程与JavaScript引擎是互斥的,当JavaScript引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JavaScript引擎空闲时当即被执行。后端
<script> btn.onclick=function() { div.style.height="900px"; //为何不先到900而后在到100px? div.style.height="100px"; } </script>
事件触发线程,当一个事件被触发时,该线程会把事件添加到待处理队列的队尾,等待JavaScript引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeout、也可来自浏览器内核的其余线程如鼠标点击、Ajax异步请求等,但因为JavaScript的单线程关系,全部这些事件都得排队等待JavaScript引擎处理(当线程中没有执行任何同步代码的前提下才会执行异步代码)。[2]浏览器
console.log(1) setTimeout(function() { console.log(2) }, 0) console.log(3) // 输出结果1,3,2
以下图,耗时JS的同步加载会阻拦页面的渲染,这时候若是有一个线程能够处理这个耗时js就行了。Web Worker能够建立一个新的进程,来和UI主线程并发运行。可是这个新进程不能操做Dom对象, 只能用来处理复杂的JS的操做。
<html> <script src="耗时.js"></script> <body> <div>123</div> </body> </html>
使用方法:
// main.js var worker = new Worker("task.js"); worker.postMessage( { id:1, msg:'Hello World' } ); worker.onmessage=function(message){ var data = message.data; console.log(JSON.stringify(data)); worker.terminate(); }; worker.onerror=function(error){ console.log(error.filename,error.lineno,error.message); } // task.js onmessage = function(message){ var data=message.data; data.msg = 'Hi from task.js'; postMessage(data); }
能够看到,两个js之间经过事件通信。尽管Web Worker在大量数据的检索、数据运算上能提供一些帮助,可是使用面仍是比较窄的。