最近在开发小程序,与vue相似,它们都有生命周期这回事。css
onLoad 监听页面加载html
onReady 监听页面初次渲染完成前端
onShow 监听页面显示vue
究竟是什么意思?android
因此这又触碰到了个人知识盲区,不过项目在磕磕绊绊中完成的差很少了,可是遇到了CSS3动画渲染的性能问题,因此我也是被逼的,再回过头来从浏览器渲染网页的流程出发,去找动画卡顿的症结。ios
浏览器渲染网页的流程以下:css3
使用 HTML 建立文档对象模型(DOM)web
使用 CSS 建立 CSS 对象模型(CSSOM)chrome
基于 DOM 和 CSSOM 执行脚本(Scripts)json
合并 DOM 和 CSSOM 造成渲染树(Render Tree)
使用渲染树布局(Layout)全部元素
渲染(Paint)全部元素
能够结合Alon的这篇前端性能优化和安卓开发者选项的显示页面布局。
如何判断手机app是native,webview仍是hybird?
简单说下,app中的一大块是白色的没有红线标记出来的,可是上面有按钮,图片等时,就是webview,也就是经过一个伪浏览器去请求到的数据,断网时打开app没有任何东西显示在上面
onLoad 监听页面加载
在渲染完界面以后,也就是经过.json中的配置项生成native界面后,开始渲染webview的部分,一个页面只会调用一次。
onReady 监听页面初次渲染完成
一个页面只会调用一次,表明页面已经准备稳当,能够和视图层进行交互。
onShow 监听页面显示
每次打开页面都会去调用其中的函数。
应该放在onShow里,由于这样我每次打开都能看到动画。
有一个前提必需要提,前端开发者们都知道,浏览器是单线程运行的。可是咱们要明确如下几个概念:单线程,主线程和合成线程。
虽说浏览器执行js是单线程执行(注意,是执行,并非说浏览器只有1个线程,而是运行时,runing),但实际上浏览器的2个重要的执行线程,这 2 个线程协同工做来渲染一个网页:主线程和合成线程。
通常状况下,主线程负责:运行 JavaScript;计算 HTML 元素的 CSS 样式;页面的布局;将元素绘制到一个或多个位图中;将这些位图交给合成线程。
相应地,合成线程负责:经过 GPU 将位图绘制到屏幕上;通知主线程更新页面中可见或即将变成可见的部分的位图;计算出页面中哪部分是可见的;计算出当你在滚动页面时哪部分是即将变成可见的;当你滚动页面时将相应位置的元素移动到可视区域。
缘由就是主线程和合成线程的调度不合理。
下面来详细说一下调度不合理的缘由。
在使用height,width,margin,padding做为transition的值时,会形成浏览器主线程的工做量较重,例如从margin-left:-20px渲染到margin-left:0,主线程须要计算样式margin-left:-19px,margin-left:-18px,一直到margin-left:0,并且每一次主线程计算样式后,合成进程都须要绘制到GPU而后再渲染到屏幕上,先后总共进行20次主线程渲染,20次合成线程渲染,20+20次,总计40次计算。
主线程的渲染流程,能够参考浏览器渲染网页的流程:
使用 HTML 建立文档对象模型(DOM)
使用 CSS 建立 CSS 对象模型(CSSOM)
基于 DOM 和 CSSOM 执行脚本(Scripts)
合并 DOM 和 CSSOM 造成渲染树(Render Tree)
使用渲染树布局(Layout)全部元素
渲染(Paint)全部元素**
也就是说,主线程每次都须要执行Scripts,Render Tree ,Layout和Paint这四个阶段的计算。
而若是使用transform的话,例如tranform:translate(-20px,0)到transform:translate(0,0),主线程只须要进行一次tranform:translate(-20px,0)到transform:translate(0,0),而后合成线程去一次将-20px转换到0px,这样的话,总计1+20计算。
可能会有人说,这才提高了19次,有什么好性能提高的?
假设一次10ms。
那么就减小了约190ms的耗时。
会有人说,辣鸡,才190ms,无所谓。
那么若是margin-left是从-200px到0呢,一次10ms,10ms*199≈2s。
还会有人说,辣鸡,也就2s,无所谓。
你忘了单线程这回事了吗?
若是网页有3个动画,3*2s=6s,就是6s的性能提高。
因为数据是猜想的,因此暂时不考虑其真实性,文章后面我使用chrome devtools的performance作了一个实验。
要知道,在"客户至上"的今天,好的用户体验是全部产品的必须遵照的一条规则,不管是对于开发者仍是产品经理,追求极致的性能都是咱们打造一个好的产品所必备的品质。
可能看了个人略不专业的分析后,你们对主线程,合成线程以及它们在2种性能不一样动画方案上的工做流程还不是很了解,能够去看一篇翻译过来的博客(英文原版连接已经失效了):深刻浏览器理解CSS animations 和 transitions的性能问题
这篇文章完美讲述了浏览器主线程和合成线程的区别,而且举了一个高度从100px变化到200px的2种动画方案的对比,对主线程和合成线程的整个工做流程作了很详尽的讲解,真心建议认真阅读一遍。
回过头来总结下,css3动画卡顿的解决方案:
在使用css3 transtion作动画效果时,优先选择transform,尽可能不要使用height,width,margin和padding。
transform为咱们提供了丰富的api,例如scale,translate,rotate等等,可是在使用时须要考虑兼容性。但其实对于大多数css3来讲,mobile端支持性较好,desktop端支持性须要格外注意。
补充:为了加强本文的说服力,特意回家作了一个实验,代码以下。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.margin-transition{
/* margin-left: 0; */
background: rgba(0,0,255,0.3);
transition: margin-left 1s;
}
.transform-transition{
/* transform: translate(0,0); */
background: rgba(0,255,0,0.3);
transition: transform 1s;
}
.common{
height: 300px;
width: 300px;
}
</style>
</head>
<body>
<div class="margin-transition common" id="marginTransition">
<p>transition:margin-left 1s</p>
</div>
<div class="transform-transition common" id="transformTransition">
<p>transition:tranform 1s</p>
</div>
<button id="control">见证奇迹</button>
<script>
var btn = document.getElementById('control');
var marginTransition = document.getElementById('marginTransition');
var transformTransition = document.getElementById('transformTransition');
btn.addEventListener("click",function(){
console.log(marginTransition.style,transformTransition.style)
marginTransition.style.marginLeft = "500px";
transformTransition.style.transform = "translate(500px,0)"
})
</script>
</body>
</html>
我将主要借助chrome devtools的performance工具对比两者的性能差别。
先来看margin动画,动态修改DOM节点的margin-left值从0到500px;。
transition: margin-left 1s;
再来看下transform动画,动态修改DOM节点的transform值从translate(0,0)到translate(500px,0)。
transition: transform 1s;
可能图片不是很好地能说明性能差别,那么咱们来列一张耗时对比表,方便咱们计算。
耗时 | margin | transform |
---|---|---|
Summery | 3518ms | 2286ms |
Scripting | 1.8ms | 2.9ms |
Rendering | 22.5ms | 6.9ms |
Painting | 9.7ms | 1.6ms |
Other | 39.3ms | 25.2ms |
Idle( browser is waiting on the CPU or GPU to do some processing) | 3444.4ms | 2249.8ms |
GPU使用率 | 4.1MB | 1.7MB |
经过上表咱们能够计算出明margin,transform与transition组合实现CSS3动画效果时的性能差别参数。
关键性能参数 | margin | transform |
---|---|---|
实际动画耗时(总时间 减去 空闲时间) | 73.6ms | 36.2ms |
计算得出,transform动画耗时约等于margin动画耗时的0.49倍,性能优化50%。
因为我对Other的所作的具体事情不是很清楚,因此这里的实际动画时间也有可能还要减掉Other中的时间,下表是咱们减掉后的数据。
关键性能参数 | margin | transform |
---|---|---|
实际动画耗时(总时间 减去 其余时间和空闲时间) | 34.3ms | 11ms |
计算得出,transform动画耗时约等于margin动画耗时的0.32倍,性能优化接近70%。
也就是说,不管咱们减去仍是不减去Other的时间,咱们采用transform实现动画的方式都比margin动画快。
不精确的得出一个小结论:transform比margin性能好50%~70%。
虽然会有50%~70%的性能提高,可是须要注意硬件差别,硬件好的状况下可能不能发现卡顿或者其余的一些性能上的问题。
例如在开发小程序的过程当中,模拟器是位于desktop端的,所以它的硬件性能性能更好,例如CPU,GPU。可是一旦在mobile端运行,例如ios或者android上运行时,就可能会出现性能问题,这就是由于移动端的硬件条件逊于PC端致使的。
因此说,性能问题是一直存在的,只不过硬件差别会致使性能影响的程度不一样。
因此咱们再次回过头来,总结出css3动画卡顿的解决方案:
在使用css3 transtion作动画效果时,优先选择transform,尽可能不要使用height,width,margin和padding。