咱们看几张的经典流程图html
咱们一直都在说Javascript是单线程,但浏览器是多线程的,在内核控制下互相配合以保持同步,主要的常驻线程有:web
负责渲染界面,解析HTML,CSS,构建DOM和Render树布局绘制等。若是过程当中遇到Javascript引擎执行会被挂起线程,GUI更新保存在一个队列中等待Javascript引擎空闲才执行;浏览器
负责解析运行Javascript;执行时间过程会致使页面渲染加载阻塞;缓存
浏览器用以控制事件循环。当Javascript引擎执行过程当中触发的事件(如点击,请求等)会将对应任务添加到事件线程中,而当对应的事件符合触发条件被触发时会把对应任务添加处处理队列的尾部等到Javascript引擎空闲时处理;性能优化
由于Javascript引擎是单线程容易阻塞,因此须要有单独线程为setTimeout和setInterval计时并触发,一样是符合触发条件(记时完毕)被触发时会把对应任务添加处处理队列的尾部等到Javascript引擎空闲时处理;W3C标准规定时间间隔低于4ms被算为4ms。网络
XMLHttpRequest在链接后浏览器新开线程去请求,检测到状态变化若是有设置回调函数会产生状态变动事件,而后把对应任务添加处处理队列的尾部等到Javascript引擎空闲时处理;多线程
经过 GPU 执行,真正将页面绘制并输出到屏幕上app
渲染流程主要步骤:异步
整个过程是一个深度遍历的操做,它会从当前节点从上往下逐个构建完以后才会去构建同层级节点及其子节点,最后的结构我网上随便找了一张图,大概以下.ide
可是这个过程是能够被CSS或者Javascript加载而阻塞,这是浏览器的一个处理机制,由于这二者均可能会改变DOM树结构的变化,因此会等它们执行完以后再继续解析
这里是跟DOM树同时生成的,这里包含了link, style和内联多份不一样的样式整合解析成一份最终的规则,整个结构也是相似DOM树的属性结构,最后的结构我也是网上随便找了一张图,大概以下.
样式的整合计算是个很复杂的过程,存在默认样式,权重,继承,伪元素,重复定义,单位换算等多种不一样程度的难题
权重规则大概以下:
实际上浏览器 CSS 选择器的解析规则是从右往左的,每一步都能过滤掉些不符合规则的分支状况, 直到找到根元素或知足条件的匹配规则的选择器就结束这个分支的遍历.因此尽可能避免深层嵌套 CSS, 由于寻找选择器和计算最终样式都会受影响的.
DOM树和CSSOM树是根据代码解析而成的,而代码最终给到浏览器渲染的确定是视觉上的表现结构,由于它们都带有字体,颜色,尺寸,位置甚至是否存在的样式控制,最后的结构我也是网上随便找了一张图,大概以下.
总的来讲,会遍历整个DOM树节点,忽略不可见节点(例如 meta,header 以及指定了属性 display: none等节点),得出各个节点的CSS定义以及他们的从属关系,从而去计算出每一个节点在屏幕中的位置
页面布局以可见区域为画布,从左到右从上往下从根节点开始布局.遍历Render树调用渲染器的API绘制节点内容填充屏幕进行像素级信息计算与绘制
实际上这一步绘制是在多个层上进行绘制
实际上在paint
以后,display
以前还有一个环节叫渲染层合并
对页面中 DOM 元素的绘制是在多个层上进行的。在每一个层上完成绘制过程以后,浏览器会将全部层按照合理的顺序合并成一个图层,而后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤为重要,由于一旦图层的合并顺序出错,将会致使元素显示异常。(下面会详解)
这通常是解析过程或者中间样式结构被改变须要从新进行计算布局才会发生,
回流:当浏览器发现变化影响了布局须要从新计算
重绘:只影响当前元素的视觉效果而不会影响其余元素
回流是影响页面性能的重要因素之一,尽可能避免
这不是一个按部就班的过程,浏览器为了尽快渲染界面展现给用户看,从网络请求获取到文档内容的同时就开始局部渲染,而不会等全部HTML解析完才会建立渲染.并且这是基本的流程,实际上如今主流浏览器会有些区别,也会优化整个渲染流程,因此这个过程实际上并无咱们想象中的这么慢
咱们就以Chrome
为例
在 Chrome 中其实有几种不一样的层类型:
DOM树每一个节点都有一个对应的渲染对象(RenderObject)
,当它们处于一个相同的坐标空间(z轴)就会共同造成一个渲染层.,从上面知道以坐标空间区分不一样的渲染层,因此
而可以知足条件的状况有:
如下任意属性值不为 none 的元素:
摘抄自层叠上下文
DOM节点和渲染对象是一一对应的,知足上面条件的渲染对象拥有独立的渲染层,不知足的将与其第一个拥有渲染层的父元素共用同一个.简单来讲,RenderObject决定渲染内容,而RenderLayers决定绘制顺序.
每一个 GraphicsLayer
对应着一个渲染层是负责最终呈现的内容图形层,它拥有一个图形上下文(GraphicsContext)
负责输出该层的位图.储存在共享内存的位图将做为纹理上传到GPU,最后由GPU将多个位图进行合成绘制.每一个GraphicsLayer能够独立的进行渲染而不会相互影响,那么将一些频繁重绘的元素放到单独的GraphicsLayer中就不会对整个页面形成影响
因此 GraphicsLayer 是一个重要的渲染载体和工具,但它并不直接处理渲染层,而是处理合成层。
某些特殊的渲染层会被提高至合成层(Compositing Layers)
,提高的前提是必须为 SelfPaintingLayer
(能够认为就是上面提到的 NormalPaintLayer
).合成层拥有单独的 GraphicsLayer,而其余不是合成层的渲染层,则和其第一个拥有 GraphicsLayer 父层共用一个。
当知足如下条件的渲染层会被浏览器自动提高为合成层
重叠或者说部分重叠在一个合成层之上。(下面隐式合成会讲到)
overflow:auto
仍是 overflow:scrill
,只要是能 scroll 便可) 的元素同一个合成层重叠,则其可视子元素也同该合成层重叠好比一个元素的 CSS 动画效果,动画运行期间,元素是有可能和其余元素有重叠的。针对于这种状况,因而就有了 assumedOverlap 的合成层产生缘由,即便动画元素视觉上并无和其兄弟元素重叠,但由于 assumedOverlap 的缘由,其兄弟元素依然提高为了合成层。
须要注意的是该缘由下,有一个很特殊的状况:
若是合成层有内联的 transform 属性,会致使其兄弟渲染层 assume overlap,从而提高为合成层。
合成层拥有单独的GraphicsLayers,而其余渲染层则和第一个拥有GraphicsLayers 的父层共用一个
部分渲染层在一些特定场景下,会被默认提高为合成层,举例来讲
transform: translateZ(0)
提高至合成层以后,按理说应该会层级更高,可是实际上两个元素都被提高到合成层,这是由于浏览器为了纠正层叠顺序保证视觉效果一致,隐性强行提高了本来高于底层元素层级的元素至合成层一些合成层的条件十分隐蔽,致使产生了不在预期范围内的合成层,达到必定数量以后会严重消耗性能占用 GPU 和大量的内存资源引发页面卡顿,造成层爆炸.咱们看下面代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> @keyframes slide { from { transform: none; } to { transform: translateX(100px); } } .animating { width: 300px; height: 30px; background-color: orange; color: #fff; animation: slide 5s alternate linear infinite; } #ul { margin-top: -20px; padding: 5px; border: 1px solid #000; } li { width: 600px; height: 30px; margin-bottom: 5px; background-color: blue; color: #fff; position: relative; /* 会致使没法压缩:squashingClippingContainerMismatch */ overflow: hidden; } p { position: absolute; top: 2px; left: 2px; font-size: 16px; line-height: 16px; padding: 2px; margin: 0; background-color: green; } </style> </head> <body> <div class="animating">composited animating</div> <ul id="ul"></ul> </body> <script> window.onload = function() { var $ul = document.getElementById('ul'); for (var i = 0; i < 10; i++) { var ulObj = document.createElement("li"); var pObj = document.createElement("p"); pObj.innerText = i // ulObj.appendChild(pObj); $ul.appendChild(ulObj); } } </script> </html>
实验可得10个左右已经开始卡顿,100就基本卡死了.再看控制台如今层的状况
形成层爆炸的缘由由于知足了如下状况:
assumedOverlap
的缘由,其兄弟元素依然提高为了合成层。因此li元素都被提高到合成层,若是单单这种状况仍是能层压缩的overflow: hidden
,当渲染层同合成层有不一样的裁剪容器(clipping container)时,该渲染层没法压缩(squashingClippingContainerMismatch)最佳方案是打破 overlap 的条件,也就是说让其余元素不要和合成层元素重叠。
让其余元素不和合成层重叠
.animating { ... position: relative; z-index: 1; }
浏览器会对多个渲染层同一个合成层重叠时进行优化,这些渲染层会被压缩到一个 GraphicsLayer 中,以防止因为重叠缘由致使可能出现的“层爆炸”,继续用上面的例子继续加元素
能够发如今提高到合成层元素之上的多个不一样元素会共同提高至同一个合成层,但也有不少没法压缩的状况.但也不是必然,也有不少没法压缩的状况
没法进行会打破渲染顺序的压缩(squashingWouldBreakPaintOrder)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> #container { position: relative; width: 420px; height: 80px; border: 1px solid black; } #composited { width: 100%; height: 100%; transform: translateZ(0); } #ancestor { -webkit-mask-image: -webkit-linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0)); } #overlap-child { position: absolute; left: 0; top: 10px; bottom: 0px; width: 100%; height: 60px; background-color: orange; } </style> </head> <body> <div id="container"> <div id="composited">Text behind the orange box.</div> <div id="ancestor"> <div id="overlap-child"></div> </div> </div> </body> </html>
在本例中,#overlap-child
同合成层重叠,若是进行压缩,会致使渲染顺序的改变,其父元素 #ancestor
的 mask 属性将失效,所以相似这种状况下,是没法进行层压缩的。目前常见的产生这种缘由的状况有两种,一种是上述的祖先元素使用 mask 属性的状况,另外一种是祖先元素使用 filter 属性的状况
当渲染层同合成层有不一样的裁剪容器(clipping container)时,该渲染层没法压缩(squashingClippingContainerMismatch)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> .clipping-container { overflow: hidden; height: 10px; background-color: blue; } .composited { transform: translateZ(0); height: 10px; background-color: red; } .target { position: absolute; top: 0px; height: 100px; width: 100px; background-color: green; color: #fff; } </style> </head> <body> <div class="clipping-container"> <div class="composited"></div> </div> <div class="target">不会被压缩到 composited div 上</div> </body> </html>
本例中 .target
同 合成层 .composited
重叠,可是因为 .composited
在一个 overflow: hidden
的容器中,致使 .target
和合成层有不一样的裁剪容器,从而 .target
没法被压缩。
相对于合成层滚动的渲染层没法被压缩(scrollsWithRespectToSquashingLayer)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> body { height: 1500px; overflow-x: hidden; } .composited { width: 50px; height: 50px; background-color: red; position: absolute; left: 50px; top: 400px; transform: translateZ(0); } .overlap { width: 200px; height: 200px; background-color: green; position: fixed; left: 0px; top: 0px; } </style> </head> <body> <div class="composited"></div> <div class="overlap"></div> </body> </html>
红色的 .composited
提高为了合成层,, 当滑动页面,.overlap
重叠到 .composited
上时,.overlap
会因重叠缘由提高为合成层,同时,由于相对于合成层滚动,所以没法被压缩(原文一开始说只有composited是合成,重叠以后overlap才会提高,可是我试验是一开始就都提高了)
再回顾一下流程图
RenderObject
,里面包含了关于浏览器怎么渲染节点的信息,若是某些节点不被渲染则不会生成对应的RenderObject
,而RenderObject
的做用就是向GraphicsContext
发出绘制的调用来进行元素的绘制绘制部分摘抄自了解浏览器渲染的过程和原理
中央处理器(CPU,central processing unit)做为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元。
在计算机体系结构中,CPU 是对计算机的全部硬件资源(如存储器、输入输出单元) 进行控制调配、执行通用运算的核心硬件单元。CPU 是计算机的运算和控制核心。计算机系统中全部软件层的操做,最终都将经过指令集映射为CPU的操做。
图形处理器(英语:Graphics Processing Unit,缩写:GPU),又称显示核心、视觉处理器、显示芯片,是一种专门在我的电脑、工做站、游戏机和一些移动设备(如平板电脑、智能手机等)上作图像和图形相关运算工做的微处理器。
GPU使显卡减小了对CPU的依赖,并进行部分本来CPU的工做,尤为是在3D图形处理时GPU所采用的核心技术有硬件T&L(几何转换和光照处理)、立方环境材质贴图和顶点混合、纹理压缩和凹凸映射贴图、双重纹理四像素256位渲染引擎等,而硬件T&L技术能够说是GPU的标志。
它不仅仅存储图形,并且能完成大部分图形功能,这样就大大减轻了CPU的负担,提升了显示能力和显示速度。
从上可得,当CPU处理好位图信息交给GPU渲染可以极大解放CPU负担,也能快速渲染图层.固然过分使用会致使严重的性能降低,内存占用太高