动画作多了,天然就要考虑性能,我打算出一个系列的日志,详细的讲解一下网页动画性能相关的知识,若是你已经能够运用css3 canvas来作动画,能够来参考一下。css
<!--more-->
目前我作的最复杂的动画就是360搜索中PC端的天气动画。html
<img src="https://static.imwineki.cn/st...; width="300" height="200">css3
共包含14个动画场景,每一个场景基本由1-3个独立的动画叠加而成,抽象动画共12个,从开发到优化完成共分为四期完成,一二期全部的动画均使用canvas完成,三期四期对动画性能进行大幅度改进,重构了部分代码。其中兼容低倍屏、高倍屏,canvas绘制的折线图浏览器兼容到IE6(具体实现参见:基于canvas折线图统计图),动画兼容到IE9,低版本浏览器动画显示静态图片。因此如下我全部分析均依赖于该项目。git
首先咱们先来简单的介绍一下动画原理,其实动画自己是不动的,它的实现原理是利用人眼的“视觉暂留”现象,在段时间内连续播放数副精致的画面,使肉眼银视觉残象产生错觉,而产生“动”的概念。github
相关概念
<li>帧 (Frame):在动画过程当中,每一幅静止画面即为一“帧”。web
<li>帧率(Frame per second):即每秒钟播放的静止画面的数量,单位是fps(Frame per second)。chrome
<li>帧时长:每一幅静止画面的停留时间,单位通常是ms(毫秒)。canvas
<li> 跳帧(掉帧/丢帧):在帧率固定的动画中,某一帧的时长远高于平均帧时长,致使其后续数帧被挤压而丢失的现象。segmentfault
正常状况下浏览器渲染刷新频率稳定在60fps左右,人眼是能够看到流畅平滑的动画的,通常来说低于30fps的动画,就会有卡顿。浏览器
来了解一下,怎样使用chrome这把利刃。
FPS Meter
使用这个工具你能够检测当前浏览器GPU渲染动画的帧率。
<img src="https://static.imwineki.cn/st...; width=100 height=80>
固然以上只能在chrome中进行调试,若是你想在其余的浏览器FPS的检测,你可使用stats.js,侦听全局或指定位置的帧率,JS实现,全部浏览器可用。
Timeline
具体使用方式能够参考:chrome官方文档
profiles
taskmanager
各厂出品的浏览器所用的渲染引擎不尽相同: IE使用Trident ,FireFox使用Gecko ,Safari使用WebKit ,Chrome 28+ 和 Opera 15+使用的是Blink(WebKit的分支)
现代的浏览器一般会有两个重要的执行线程,这2个线程协同工做来渲染一个网页:
<li>主线程
<li>合成线程
通常状况下,主线程负责:
<li>运行js
<li>计算HTML元素的css样式
<li>页面布局layout
<li>将元素绘制到一个或多个位图中
<li>将这些位图交给合成线程
合成线程负责:
<li>经过GPU将位图渲染到屏幕
<li>通知主线程更新页面中可见或即将变成可见的部分的位图
<li>计算页面中可见部分
<li>计算出当你在滚动页面时哪部分是即将变成可见的
<li>当你滚动页面时将相应位置的元素移动到可视区域
长时间执行 JavaScript 或渲染一个很大的元素会阻塞主线程,在这期间,它将没法响应用户的交互。
相反,合成线程则会尽可能去响应用户的交互。当一个页面发生变化时,因为当今大多数设备的屏幕刷新率都是 60次/秒,因此合成线程也会以每秒60 帧的间隔去不断重绘这个页面,即便这个页面不完整。
当用户滚动页面时,合成线程会通知主线程更新页面中最新可见部分的位图。可是,若是主线程响应地不够快,合成线程不会保持等待,而是立刻绘制已经生成的位图,还没准备好的部分用白色进行填充。
也就是说js是单线程的,但浏览器是多线程的,感兴趣的小伙伴能够看一下我以前翻译的谷歌日志浏览器多进程架构。
大多数设备的屏幕刷新率都是 60次/秒,浏览器对每一帧画面的渲染工做须要在16毫秒(1秒 / 60 = 16.66毫秒)以内完成。但实际上,在渲染某一帧画面的同时,浏览器还有一些额外的工做要作(好比渲染队列的管理,渲染线程与其余线程之间的切换等等)。所以单纯的渲染工做,通常须要控制在10毫秒以内完成,才能达到流畅的视觉效果。若是超过了这个时间限度,页面的渲染就会出现卡顿效果,也就是常说的jank,它是很糟糕的用户体验。
在web页面中,代码就是通过大概如下步骤转换成屏幕上的显示像素:
1.JavaScript:通常来讲,咱们会使用JavaScript来实现一些视觉变化的效果。
2.计算样式:这个过程是根据CSS选择器,好比.headline或.nav > .nav_item,对每一个DOM元素匹配对应的CSS样式。这一步结束以后,就肯定了每一个DOM元素上该应用什么CSS样式规则。
3.布局:上一步肯定了每一个DOM元素的样式规则,这一步就是具体计算每一个DOM元素最终在屏幕上显示的大小和位置。web页面中元素的布局是相对的,所以一个元素的布局发生变化,会联动地引起其余元素的布局发生变化。好比,<body>元素的宽度的变化会影响其子元素的宽度,其子元素宽度的变化也会继续对其孙子元素产生影响。所以对于浏览器来讲,布局过程是常常发生的。
4.绘制:本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等,也就是一个DOM元素全部的可视效果。通常来讲,这个绘制过程是在多个层上完成的。
5.渲染层合:由上一步可知,对页面中DOM元素的绘制是在多个层上进行的。在每一个层上完成绘制过程以后,浏览器会将全部层按照合理的顺序合并成一个图层,而后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤为重要,由于一旦图层的合并顺序出错,将会致使元素显示异常。
上述过程的每一步中都有发生jank的可能,所以必定要弄清楚你的代码将会运行在哪一步。
虽然在理论上,页面的每一帧都是通过上述的流水线处理以后渲染出来的,但并不意味着页面每一帧的渲染都须要通过上述五个步骤的处理。实际上,对视觉变化效果的一个帧的渲染,有这么三种 经常使用的 流水线:
1.JS / CSS > 计算样式 > 布局 > 绘制 > 渲染层合并
若是你修改一个DOM元素的”layout”属性,也就是改变了元素的样式(好比宽度、高度或者位置等),那么浏览器会检查哪些元素须要从新布局,而后对页面激发一个reflow过程完成从新布局。被reflow的元素,接下来也会激发绘制过程,最后激发渲染层合并过程,生成最后的画面。
2.JS / CSS > 计算样式 > 绘制 > 渲染层合并
若是你修改一个DOM元素的“paint only”属性,好比背景图片、文字颜色或阴影等,这些属性不会影响页面的布局,所以浏览器会在完成样式计算以后,跳过布局过程,只作绘制和渲染层合并过程。
3.JS / CSS > 计算样式 > 渲染层合并
若是你修改一个非样式且非绘制的CSS属性,那么浏览器会在完成样式计算以后,跳过布局和绘制的过程,直接作渲染层合并。第三种的性能最为理想,通常来讲对于动画和滚动这种复合很重的渲染,咱们就尽可能向第三种靠拢。
性能优化是一门减法艺术,咱们要本着经历简化页面徐然过程,而后使每一步的渲染尽量高效。
咱们先来讲说GPU,大多数手机、 平板电脑、 和计算机都配备了GPU芯片,GPU有着很是专业的定位,这意味着GPU很是擅长作某些事情(好比绘图),但在其余方面则没什么优点。
如今,咱们来看看CPU和GPU的内部特色
CPU(Central Processing Unit),GPU(Graphics Processing Unit)翻译过来,第一个叫作中央处理器,后者叫作视觉处理器,换言之,一样是计算机中用于计算的核心组件,CPU主要负责通用计算,GPU主要负责专用计算。咱们来看看下面的这个图理解一下:
翻译一下:
<li>_强大的ALU - 下降操做延时_
<li>_巨大的缓存器 -
将长延迟内存访问转换为短延迟缓存访问_
<li>_复杂的控制器 -分支预测用于减小分支延迟 -数据转发,减小数据延迟
_
翻译一下:
<li>_小缓存 -用来提升内存吞吐量_
<li>_小控制器 -没有分支预测,没有数据转发_
<li>_高效能ALU - 不少长延时,可是有大量的吞吐流量_
能够看到,CPU中包含Control(控制层),Cache(缓存层),ALU(算术逻辑单元),其中ALU是主要负责进行简单运算的。而GPU中则能够明显的看到包含大量的ALU模块和少许的Cache和Control模块。
算术逻辑单元(英语:Arithmetic Logic Unit, ALU)[1]是中央处理器的执行单元,是全部中央处理器的核心组成部分,由及闸和或闸构成的算数逻辑单元,主要功能是进行二进制的算术运算,如加减乘(不包括整数除法)。基本上,在全部现代CPU体系结构中,二进制都以二补数的形式来表示。 -----维基百科
因此能够清晰地从结构中看出,CPU更擅长于逻辑控制,串行运算,GPU更擅长于大规模并发计算。举一个简单的例子,一个教授,带着20个学生完成一个项目,如今项目须要处理1000次100之内的加减乘除运算,这项工做其实并不须要任何逻辑处理,只是大量的工做量的堆叠,这时,就不须要教授亲力亲为,教授能够将任务分配给这20个学生分工完成这项工做,其中教授的角色就至关于CPU,20个学生整体至关于GPU,每一个学生就等于一个ALU。
GPU的处理图像的优点:
<li>绘制位图到屏幕上
<li>一遍又一遍地绘制相同的位图
<li>将同一位图绘制到不一样位置,执行旋转以及缩放处理
<li>具备多核简单计算能力,能够处理大量计算数据
GPU的慢在于:
<li>将位图加载到它的显存中
JS动画
缺点:JavaScript在浏览器的主线程中运行,而其中还有不少其余须要运行的JavaScript、样式计算、布局、绘制等对其干扰。这也就致使了线程可能出现阻塞,从而形成丢帧的状况。
优势:JavaScript的动画与CSS预先定义好的动画不一样,能够在其动画过程当中对其进行控制:开始、暂停、回放、停止、取消都是能够作到的。并且一些动画效果,好比视差滚动效果,只有JavaScript可以完成。
CSS动画
缺点:缺少强大的控制能力。并且很难以有意义的方式结合到一块儿,使得动画变得复杂且易于出问题。
优势:浏览器能够对动画进行优化。它必要时能够建立图层,而后在主线程以外运行,也就是开启GPU加速。
通常来讲,Chrome中知足如下任意状况就会建立图层:
<li> 3D或透视变换(perspective transform)CSS属性
<li>使用加速视频解码的<video>
节点
<li> 拥有3D(WebGL)上下文或加速的2D上下文的 <canvas>
节点
<li>混合插件(如Flash)
<li> 对本身的opacity作CSS动画或使用一个动画webkit变换的元素
<li>拥有加速CSS过滤器的元素
<li>元素有一个包含复合层的后代节点(一个元素拥有一个子元素,该子元素在本身的层里)
<li>元素有一个z-index较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)
须要注意的是,若是图层中某个元素须要重绘,那么整个图层都须要重绘。好比一个图层包含不少节点,其中有个gif图,gif图的每一帧,都会重回整个图层的其余节点,而后生成最终的图层位图。因此这须要经过特殊的方式来强制gif图属于本身一个图层(translateZ(0)或者translate3d(0,0,0)),CSS3的动画也是同样。
经过web workers 这样的多线程来实现动画
好啦!基本概念已经铺垫完了,感兴趣的话,就来看看在业务线中如何小试牛刀。网页动画性能日志(二)
转载请说明出处!
参考连接:
<li>http://blog.csdn.net/leer168/article/details/25917093