H5动画优化之路
H5动画60fps之路
在移动端,和Native相比,H5一直都被人吐槽性能差,尤其是在动画方面。
谈到整个Web app的生命周期,一般分为四个部分:
- 加载
- 等待用户
- 响应用户
- 动画
一般情况下,首屏加载的时间应该小于1s
,而响应用户行为的时间应该小于100ms
,动画应该达到60fps
。这篇文章只针对动画60fps的优化。
关键渲染路径
动画性能高,从直观上来看是动画没有抖动和卡顿,从数字上是渲染达到了60fps。60fps就是每秒60帧,所以每帧的时间只有1000ms/60=16.67ms。实际上,浏览器在每一帧还要做一些额外的事情,所以如果要达成60fps,我们需要保证每一帧的时间在10ms到12ms之间。
我们先来看看浏览器在每一帧渲染都做了哪些事情。
javascript
现阶段CSS动画接口比较有限,许多复杂的动画如果css不能完成,就需要使用requestAnimationFrame
函数,这样每帧都会有JavaScript的计算。
Style
当一个新的样式应用到Dom上的时候,就会引起Style的计算,同JavaScript,如果开发者使用CSS Animation,CSS Transition,那么浏览器只有在动画开始之前会做Sytle的计算,而requireAnimationFrame会在每帧都计算。
Layout
当新的CSS样式出发了Layout,比如修改了width,height,pisition,这时浏览器需要重新Layout受到影响的元素,大部分情况下,即使一个位置很远的元素发生很小的宽度改变,也会引起整个document的layout,这在动画里是一个性能非常低的实现,应该尽量避免。
Paint
Layout变化后,受到影响的元素会重新Paint,如果遇到首次加载图片,浏览器需要将图片先解码放入内存(Image Decode)。Painting是在多个Surface上进行的,最后会出来多个Layer。
Composite
最后一步Composite就是把已经Paint好的各个Layer合成到一起。浏览器会将每个层分成多个Tiles去Paint,但是这些作为H5开发者来说是不能够控制的,这些层和Tiles信息会被传到GPU,最终由GPU负责渲染并显示在屏幕上。
三条路
并不是每个CSS的变动引起的渲染过程都要经历以上全部,实际有三条路可以走。
第一条路,比如修改元素的width,这些步骤都会执行。
第二条路:修改元素的background-color:不会有布局的变化,不会触发Layout,但是会发生Paint
第三条路:修改元素的transform,不会触发Layout,也不会触发Paint
当我们要完成一个动画时,可能有很多种实现的方式,比如让一个小球向右平移100px,我们可以用以下这些方法:
.move{left:100px};
.move{margin-left:100px};
.move{padding-left:100px};
.move{transform:translateX(100px)};
问题就在这里,使用哪种方式性能最高?
从上面看出,如果使用不触发Layout和Paint的CSS属性完成动画,性能是最高的。那么哪些CSS属性不会触发
Layout和Paint呢?
推荐一个网站CSS TRIGGERS
,这里详细的列出了所有CSS属性在修改后是否触发Layout和Paint,是个非常给力的工具!
使用Chrome的DevTools调试
调试动画就要用到timeline,这里列出3个比较实用的功能。
- 查看每帧的时间:通过录制跟踪一段动画,可以看到每一帧的情况,找到耗时超过16ms的帧可以有针对性地解决问题。
- 查看内存:通过Memory工具可以查看内存的使用情况,对于内存泄露的检查是非常有帮助的。
- 查看CompositeLayer:通过Layer可以查看当前绘制的帧有多少需要Composite的Layer,Layer越多,带来的Upate LayerTree和Composite Layer的时间就越长。
优化方法
使用requestAnimationFrame
:
前面提到,如果动画性能达到60fps,那么每一帧的时间是16ms,浏览器会有一些额外的工作,所以要保证所有的事情在10ms到12ms完成,那么留给JavaScript的时间在3ms到4ms比较合适。
大多数比较早期的Web动画是用setTimeout/setInterval这两个函数实现的,包括著名的JQuery,那个年代也没有其它的API可以用。这种实现方式性能非常低效,因为JavaScript在处理setTimeout/setInterval时,不会和渲染流程联系起来,很有可能在一帧的中间突然执行JavaScript导致Sytle和Layout等后面的处理要重新进行而不能在16ms内完成全部。
但是现在不同了,我们有了requestAnimationFrame,使用这个函数,动画每一帧在何时执行,如何执行,都由浏览器去决定,开发者只要把每次执行的工作写好就可以了。
function animate(){
//do something change here,like:
//x+=0.1;element.style.opacity=x;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
查看耗时较长的js,必要时使用WebWorker
如果在动画执行过程中,有额外的大量JavaScript计算,为了不影响动画,建议将大量计算的JavaScript放入WebWorker。WebWorker是个功能有限的实现JavaScript多线程的工具,Worker和主线程通过message事件和postMessage方法通讯,API可以参考WebWorker。
micro Optimization
V8引擎已经可以帮助我们处理这些细小的优化。但是作为一种良好的编码习惯,还是要保持。
Style优化
浏览器花多长时间处理Style的计算取决于有多少元素受到了影响,所以改变1000个元素的Style所耗费的时间,是改变10个元素的100倍。有了这个结论,我们在做每个动画时,要确保每次改变CSS时,所影响的元素都是我们需要改变的,不要改变和动画无关的元素。
避免Layput Thrashing
什么是 Layout Thrashing?先看一个例子:
for(var i=0;i<elements.length;i++){
var blockWidth=baseElement.Width;
elements[i].style.width=blockWidth;
}
这是一个性能很低的例子。
当开发者设置了一个CSS样式,浏览器会继续等待看有没有更多的样式改变,然后在接下来的一帧来个批处理。
我们再看上面那个性能低的例子,设置好一个新的样式,接着让浏览器去读一个Layout,这样浏览器就不能等待多个样式的批处理,而是强制让它先把刚才的样式做渲染,这样一读一写地循环下去,性能是非常低的,叫做“Forced Synchonous Layout”。
这个例子修改起来非常简单,只要把读Layout的事情放在循环外就好了。
var blockWidth=baseElement.Width;
for(var i=0;i<elements.length;i++){
elements[i].style.width=blockWidth;
}
Painting和Composite优化
Painting是非常耗性能的,所以为了避免Painting,我们一般会把这个元素变成一个Layer,当它成为一个单独Layer后,就会独立出来,当在它后面的其他元素需要重绘时,它也不受到影响,只是最后需要做Composite合成。但是并不是Layer越多越好,这样会加重Composite的工作,所以开发者需要在Paint和Composite上找到一个平衡点。
如何让一个元素变成Layer呢?目前有几种Hack方式:
.layer{transform:translate3d(0,0,0)}
.layer{transform:translateZ(0)}
Chrome提供了一种更好的方式:使用will-change,和上面不同,will-change不会直接把元素变为Layer,而是给浏览器一个提示,这可以让浏览器自己决定是否成为Layer,推荐这种方式:
.layer{will-change:transform;}
推荐一篇Chrome官方的文章GPU Accelerated Compositing in Chrome,这里面非常详细地讲述了从RenderObject到RenderLayer,到GraphicsLayer,最后变成Chrome Compositor Layers的一系列过程,非常详细,文章里提到的GraphicsLayer就是本文的Layer。
上面分别从JavaScript, Style, Paint的过程介绍了一些针对性的优化方法,通过使用Chrome的DevTools,开发者可以针对渲染路径上的每一个步骤优化,相信一定会有非常好的效果。
我将这些优化点简单总结为一个图:
H5动画优化之路的更多相关文章
- [转] 钉钉的H5性能优化方案
对于一个H5的产品,功能无疑很重要,但是性能同样是用户体验中不可或缺的一环.原本H5的渲染性能就不及native的app,如果不把性能优化做起来,将极大地影响用户使用产品的积极性. 用户感受 当用户能 ...
- CSS代码重构与优化之路(转)
CSS代码重构与优化之路 阅读目录 CSS代码重构的目的 CSS代码重构的基本方法 CSS方法论 我自己总结的方法 写CSS的同学们往往会体会到,随着项目规模的增加,项目中的CSS代码也会越来越多 ...
- React-Native 动画优化
前言 动画对于客户端来说是非常重要的一部分,直接影响到应用的用户体验.前端对于动画优化通常使用CSS3样式来实现动画,以利用GPU加速特性.而React-Native由于渲染模式的不同,无法使用CSS ...
- 微博MySQL优化之路--dockone微信群分享
微博MySQL优化之路 数据库是所有架构中不可缺少的一环,一旦数据库出现性能问题,那对整个系统都回来带灾难性的后果.并且数据库一旦出现问题,由于数据库天生有状态(分主从)带数据(一般还不小),所以出问 ...
- 新浪微博iOS客户端架构与优化之路
新浪微博iOS客户端架构与优化之路 随着Facebook.Twitter.微博的崛起,向UGC.PGC.OGC,自媒体提供平台的内 容消费型App逐渐形成了独特的客户端架构模式.与电商和通讯工具类 ...
- 阿里巴巴 web前端性能优化进阶路
Web前端性能优化WPO,相信大多数前端同学都不会陌生,在各自所负责的站点页面中,也都会或多或少的有过一定的技术实践.可以说,这个领域并不缺乏成熟技术理论和技术牛人:例如Yahoo的web站点性能优化 ...
- h5动画如何实现?如何快速开发h5动画
最近几年随着h5的兴起,复杂的h5动画,甚至是交互动画类型的产品不断涌现,尤其在课件产品方面,很多公司都有相关需求,最近很多h5开发工程师想了解相关方面的技术. 针对h5,如果是简单的动画效果,可以考 ...
- Golang 优化之路——bitset
写在前面 开发过程中会经常处理集合这种数据结构,简单点的处理方法都是使用内置的map实现.但是如果要应对大量数据,例如,存放大量电话号码,使用map占用内存大的问题就会凸显出来.内存占用高又会带来一些 ...
- 专访阿里巴巴研究员“赵海平”:Facebook的PHP底层性能优化之路(HipHop,HHVM)
专访阿里巴巴研究员“赵海平”:Facebook的PHP底层性能优化之路 http://www.infoq.com/cn/articles/interview-alibaba-zhaohaiping
随机推荐
- 关于Socket通讯原理
通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄. 在Internet上的主机一般运行了多个服务软件,同时提供几种服务. 每种服务都打开一个Socket,并绑定到一 ...
- [原]unity中WWW isDone方法只能在主线程中调用
项目中要使用动态加载,原计划是生成WWW对象后,放到一个容器里.由一个独立线程轮询容器里的对象,如果www.isDone为true时,回调一个接口把结果交给请求方. new Thread( new T ...
- 在 Transact-SQL 中使用 TRY...CATCH
在 Transact-SQL 中使用 TRY...CATCH (注:本文来自于 http://msdn.microsoft.com/zh-cn/library/ms179296.aspx) ...
- c# 远程监控(1) 大纲
此篇文章主要讲了如何使用C# Winform程序模拟一个远程监控系统,并使用RTP实时传输协议传输数据. 应用场景:远程监控.局域网视频会议.客户端流式缓冲播放 这方面的资料还是有一些,但是都需要整合 ...
- ionic+cordova+angularJs监听刷新
普通的js返回并刷新这里就不多说了,百度就有很多方法. 下面说的是使用了angularjs.ionic开发的一个手机app中我使用的返回上一页并刷新的方法. 场景:回复的页面是单独的,点击保存回复后会 ...
- MYSQL数据库间同步数据
http://blog.csdn.net/swandy45/article/details/6982421 环境要求: Windows 操作系统 需要Mysql 3.23.15以后的版本. 假设数据库 ...
- 暑假集训(3)第四弹 -----Frogger(Poj2253)
题意梗概:青蛙王子最近喜欢上了另一只经常坐在荷叶上的青蛙公主.不过这件事不小心走漏了风声,被某fff团团员知 道了,在青蛙王子准备倾述心意的那一天,fff团团员向湖泊中注入大量的充满诅咒力量的溶液.这 ...
- poj 3565 uva 1411 Ants KM算法求最小权
由于涉及到实数,一定,一定不能直接等于,一定,一定加一个误差<0.00001,坑死了…… 有两种事物,不难想到用二分图.这里涉及到一个有趣的问题,这个二分图的完美匹配的最小权值和就是答案.为啥呢 ...
- 【Linux工具】svn命令行使用实例
引言 网上有这么多介绍 svn 使用的文章,为什么还要写?因为它们深入不浅出,平铺不分类,理论不实际,看完也记不住. 本文先介绍基本用法,后进行实例演练.不求大而全,只求熟练常用,自行用 svn he ...
- glDatePicker-2.0 日历插件
昨天用的日历插件在绑定数据的时候出现了问题,所以今天换了这个glDatePicker-2.0 日历插件 这是我修改后的样式 默认样式是这样的. 我的代码 index.html <!doctype ...