浏览器是多进程模型。chrome浏览器主要包括如下进程类型javascript
进程模型有如下特征:html
经过chrome浏览器右上角的三个点--More Tools--Task Manager能够查看当前浏览器所开启的进程。注:三个tab共享一个进程的状况是在第一个Tab打开了另外两个tabjava
每个进程内部,都有不少线程。web
Browser进程下有不少线程:chrome
其中线程1 Chrome是主线程。Chrome IOThread线程就是IO线程。中间还有用来处理视频、存储、王阔、文件、音频、浏览历史等的线程。canvas
Render进程下有如下线程浏览器
其中线程Chrome是主线程,Chrome IOThread线程就是IO线程。线程2是一个新的线程,用来解释HTML文档。缓存
网页的加载和渲染过程的基本工做方式以下:服务器
HTML支持的资源大体有:Html/Js/CSS/图片/svg/视频、音频等,资源在加载过程当中分为在缓存中和不在缓存中两种状况。网络
例如在解析Html过程当中,发现一个img标签,webkit会专门建立一个ImageLoader去加载该资源。因为获取资源耗时较长,一般是异步执行的,也就是说资源的获取和加载不会阻碍当前Webkit的渲染过程,例如图片/CSS。
固然某些资源例如JS会阻碍主线程的渲染。Webkit会怎么作呢?当前的主线程被阻碍时,webkit会另起一个线程去遍历后面的HTML网页,收集须要的资源URL,发送请求。这样就能够避免被阻碍。与此同时,Webkit可以并发下载这些资源,甚至并发下载JS代码资源,这种机制对于网页的加速加载非常明显。
这个地方说法跟一般讲的将script标签加上async属性或者放在body结束标签的前面来提高性能的说法不太一致。书中给出的解释是,就算webkit有本身的优化策略,但仍是建议加上async属性或者放在body结束标签的前面,由于并非全部的渲染引擎都做了如此的考虑
缓存资源池是有限的,必须有响应的机制来替换其中的资源,这个机制就是LRU(Last Recent Used)最少使用原则。
网络请求中,DNS解析和TCP链接占用大量的时间。网页开发者能够从如下方面着手减小这一部分时间
<Link rel="dns-prefetch" href="...">
减小资源的数量
在Render进程中有一个线程,该线程用来处理HTML文档的解释任务。由于JS代码可能会修改文档结构,因此JS代码的执行会阻塞后面节点的建立,同时也会阻碍后面的资源下载。因此有两点建议
建议1、
<html> <head> <script type="" async> ... </script> </head> <body> <img src="" /> </body> <html>
建议2、
<html> <head> </head> <body> <img src="" /> <script type=""> ... </script> </body> <html>
但其实在执行JS代码时,webkit有本身的优化机制,webkit会先暂停JS执行,扫描后面的词语,若是发现有其它资源,使用预资源加载器来发送请求,在这以后才执行JS代码。尽管如此,仍是推荐按建议的写代码,毕竟不是全部的渲染引擎都作了考虑。
事件分为3个阶段,1事件捕获阶段,2处于目标事件阶段,3冒泡阶段,可使用event.phase获取当前所属的阶段。使用addEventListner默认是在冒泡阶段捕获事件,除非最后一个参数制定个为true;
大多数状况下,都是将事件处理程序添加到事件流的冒泡阶段,能够最大程度兼容各类浏览器。最好只在须要在事件到达目标以前捕获它时才添加到捕获阶段。
<html> <body id="body"> <div id="div"> <span id="span">span元素</span> </div> <script type="text/javascript"> function onSpan(event) { console.log('on span'); } function onDiv(event) { console.log('on div'); } function onBody(event) { console.log('on body'); } window.onload = function () { const spanEle = document.getElementById('span'); spanEle.addEventListener('click', onSpan); const divEle = document.getElementById('div'); divEle.addEventListener('click', onDiv); const bodyEle = document.getElementById('body'); bodyEle.addEventListener('click', onBody, true); } </script> </body> </html>
点击span后代码执行顺序为 body、 span、 div
在chrome的console中使用document查看当前页面的DOM树结构。当渲染引擎接收到 CSS 文本时,会执行一个转换操做,将 CSS 文本转换为浏览器能够理解的结构——styleSheets。在控制台中输入 document.styleSheets就能够看到对应的结构。总结以下
由于页面中有不少复杂的效果,如一些复杂的 3D 变换、页面滚动、video节点,或者使用 z-indexing 作 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还须要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。
具体如下状况会生成单独的合成层:
每一个RenderLayer对象能够被想象成图像中的一个层,各个层一同构成了一个图像,在渲染过程当中,每一个层对应网页中的一个或者一些可视元素,这些元素绘制内容到该层上,把这个过程称为绘图操做。若是绘图操做须要GPU完成,称之为GPU硬件加速绘图。理想状况下,每一个层都有个绘制的存储区域,这个存储区域用来保存绘图的结果。最后,须要将这些层的内容合并到同一个图像中,称之为合成。
网页分层有两个缘由:一是为了方便网页开发者开发网页并设置网页的层次;二是为了webkit处理上的遍历,也就是为了简化渲染逻辑。
从输入网页URL到构建完DOM树这个过程:
接下来就是Webkit利用CSS和DOM树构建RenderObject树直到绘图上下文,具体过程以下:
网页加载后,每当从新绘制新的一帧时,通常须要通过三个阶段:计算布局--绘图--合成。其中前两个阶段比较耗时间,合成时间相对要少一些。在实际应用中,能够经过以下方法来减小webkit绘制每一帧所须要的时间:1、使用合适的网页分层技术以减小须要从新计算的布局和绘图;2、使用CSS 3D变形和动画技术。
JS语言的一个特色是它是无类型语言,没有办法在编译的时候知道变量类型,运行的时候才能肯定。在运行时计算和决定类型,会带来很严重的性能损耗。
这相较于静态语言例如C++的区别是,静态语言只须要知道变量的地址及类型,地址加上类型的长度,就能够得出该变量的值。
JS引擎就是可以将JS代码处理并执行的运行环境。JS引擎执行过程主要分为三个阶段,分别是语法分析,预编译和执行阶段。
语法分析就是经过词法分析和语法分析获得语法树的过程,若是在构造语法树的时候,发现错误,就会报错并结束整个代码块的解析。
首先了解变量对象(Variable Object, 缩写为VO)是用于存储执行上下文中的:
在函数上下文中,变量对象被表示为活动对象AO;
function test(a, b) { var c = 10; function d() {} var e = function _e() {}; (function x() {}); b=20; } test(10)
VO按照以下顺序填充:
所以
AO(test) = { a: 10, b: undefined, c: undefined, d: <ref to func "d"\> e: undefined };
AO(test) = { a: 10, b: 20, c: 10, d: <reference to FunctionDeclaration "d"\> e: function \_e() {}; };