velocity.js
性能影响一切。 明显或真实的性能提升可改善用户体验。 反过来,改善的用户体验会提高利润。
几项主要研究证明,延迟增加会大大降低收入。 必应(Bing) 报告说,延迟增加2,000毫秒会导致每用户收入下降2%。 同样,Google发现500毫秒的延迟会导致流量下降20% 。
因此,在构建高性能UI引擎的过程中 ,我同时构建了一个用户体验引擎。 本文旨在将当前的Web性能格局与实际情况进行关联,并深入研究Velocity.js(一种动画引擎,可在所有浏览器和设备上显着提高UI性能和工作流程)的性能优化。
在深入探讨Velocity之前,让我们回答紧迫的问题。 多年来,该浏览器如何可能秘密地具有巨大的性能潜能,但前端开发人员仍未充分利用它?
简短的答案:开发人员中根本缺乏Web性能意识。 让我们来探索。
网络性能概况
从UI设计的角度来看,不乏赞扬构建移动优先的响应式网站的优点的文章。 到目前为止,开发人员已经掌握了它。 相反,从UI性能的角度来看,大多数开发人员都会承认他们不知道自己在做什么。 尽管Google,Mozilla和Microsoft的拥护者撰写了无数有关性能最佳实践的文章,但大多数开发人员根本没有阅读它们。
缺乏这种认识的是动态的,通过UI设计,可以在多年的经验中自信地迭代艺术技巧。 但是,尽管性能原理(数据结构,延迟和渲染管道)受相同的迭代过程约束,但其前端实现的细节可能会定期更改。 坦率地说,注重性能的开发人员经常被浏览器怪癖和设备功能所束缚。 这种情况使得开发人员必须敏锐地意识到Web的基础体系结构层(渲染堆栈,垃圾收集和网络),以便他们可以广泛地抽象出解决性能问题的方法。
但是,由于开发人员已经掌握了工作量,因此目前的观念表明,普通开发人员精通该领域是不合理的。 为此,网络的主要性能倡导者Google的Ilya Grigorik最近对浏览器和网络性能的神话进行了逐点分析: 高性能浏览器网络 。 (其他Web性能资源可在本文底部找到。)
当前的网络性能状况类似于紧跟IE8的怪癖-一段时间后,您投入精力并简单地提高站点对旧版浏览器支持的起点。
移动设备上的情况几乎相同:开发人员告诉自己:“嗯,设备越来越快。 因此,在接下来的几个月中,随着用户继续升级其设备,我的网站自然会变得更加高效。”
不幸的是,事实恰恰相反。首先,发展中国家正在采用的智能手机无法满足我们口袋中iPhone的性能要求–您真的要放弃为下一个20亿上网用户提供产品的机会吗? 如果您的直觉是“这不是我的问题”,请放心,邪恶的Web开发者双胞胎正坐在千里之外,想着要着手开发市场的想法,然后再努力开发出令人鼓舞的解决方案即使在低功率设备上也能快速完成。
即将到来的Firefox OS计划准备将功能强大的智能手机带给亿万人民。 未来已经来临。 我们不是在说假说。 爱立信报告说,未来五年,全球智能手机用户数量将从19亿增加到59亿-几乎完全由发展中国家推动。
设置后遗忘症对网络性能的第二个危险是,开发人员系统地犯了错误,即在承受理想性能负载的设备上测试其移动页面。 但是,尝试打开更多的应用程序和网页。 现在,重新测试您的网站。 Yikes,您刚刚人工创建了一个相对“古老”的Android 2.3设备。 另外,您已经陷入第二个问题的核心:基于浏览器的应用程序对设备负载(CPU,GPU和内存使用情况)敏感。 加上设备硬件的可变性,您就开始接近移动性能的现实:您应该始终开发最快的网站,而不仅仅是在iPhone上运行良好的网站。
性能很复杂,性能很重要。 那很清楚。 但是,我们实际上可以做什么? 这就是我打算在三个月内深入研究开源开发的答案。
网络动画景观
jQuery是Web的主要动画工具,它在2006年开始开发,而它又是Web上主要的动画工具,而Velocity则是在2014年开发的。因此,它结合了全新的性能最佳实践。
简而言之,Velocity是一个轻量级CSS操作库,其动画层位于顶部。 它完全由JavaScript驱动,而不是CSS过渡。 它公开了与jQuery的$.animate()
相同的API,以简化从$.animate()
到$.velocity()
的过渡。
在Velocity之前,DOM动画领域主要由jQuery,Transit(用于通过JavaScript控制CSS转换的转到库)和GSAP(第一个高性能JavaScript动画库)组成。
这些库的缺点如下:
- jQuery的本机
$.animate()
缓慢,并且UI动画设计功能相对较轻-即使与jQuery UI配对也是如此。 - Transit比jQuery快得多,但功能甚至更轻巧,由于其通过JavaScript填充CSS过渡的特性而偶尔出现故障,并且不支持IE8和IE9(它们在全球浏览器中仍然占有很大份额) 。
- GSAP是功能强大的成熟动画平台。 它的功能几乎是无限的。 它可以对从DOM到WebGL的所有内容进行动画处理。 (相比之下,Velocity只专注于作为一种轻量级工具来极大地改善UI动画性能和工作流程。)尽管GSAP要求为各种类型的企业支付许可费,但Velocity是通过超许可的MIT许可证免费开源的。
在所有压力级别下,速度都大大超过了jQuery,而从中等压力级别开始,Transit的运行速度超过了jQuery。 GSAP的表现类似于Velocity。 有关头对UI性能的比较,请参阅Velocity的文档 。
计时器优化
![](https://i-blog.csdnimg.cn/blog_migrate/033f82e5c5c3a0711e3250b543c92611.png)
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
我们准备深入探讨多汁的性能细节。 您如何快速制作动画引擎? 是微优化吗? 不。
速度微优化为零。 这是我确定要逆转的趋势。 Stack Overflow充满了jsPerf.com的比较,这些比较好意的开发人员可以用来确定哪种基于JavaScript的实现是性能最高的。 但是,开发人员经常不考虑它们的上下文而喜欢这些面值比较。 如果一个实现每秒已经可以完成几百万次操作,那么它的替代实现有多快无关紧要。 您JavaScript代码可能永远不会以每秒数百万次操作的规模运行。
DOM性能的真正瓶颈主要是计时器创建和DOM操作。
让我们从分析计时器创建开始。 在使用setInterval()
, setTimeout()
和requestAnimationFrame()
时创建计时器。 计时器创建存在两个性能问题:1)由于浏览器维护计时器过多,一次触发过多的计时器会降低帧速率,以及2)不正确地标记动画开始的时间会导致丢帧。
Velocity解决第一个问题的方法是维持一个全局滴答循环,该循环可以一次循环遍历所有活动的Velocity动画。 不会为每个Velocity动画创建单独的计时器。 简而言之,Velocity将调度优先于中断。
通过直接在第一个动画滴答本身内部设置开始时间,可以解决第二个问题,即标记动画开始的时间,以便循环可以跟踪经过了多少时间。
相反,开发人员通常在触发动画时设置动画的开始时间。 但是,在用户单击按钮以触发UI动画的时间与实际的动画循环开始的时间之间,第三方因素(相关JavaScript逻辑,附加的UI交互,系统范围的负载,等)可能会导致延迟。 随后,当动画循环最终开始时(例如,大约16-85毫秒后),大多数动画循环的实现方式将导致丢弃大量前帧以弥补时间差异。
“速度”设置了第一个动画循环刻度内的开始时间,而不是实际触发动画时的结果,是动画有可能在触发的开始点之后约16-85ms开始播放。 但是,这种延迟实际上是无法察觉的,并且最终是无关紧要的,除非您正在创建一个游戏,而该游戏通常需要时间精确的碰撞检测。
总之,对于UI动画,应始终将平滑度放在时间精度之上。
最小化DOM操作
计时器优化只是实现Velocity(DOM的最小化)背后的实际性能优化的垫脚石。 Velocity背后的核心性能原理是,虽然您可以提供的帧速率有一个上限(大脑每秒只能感知到这么多帧),但是避免DOM操作的巧妙程度没有上限。
DOM当然是网页HTML底层的层次表示形式。 自然,DOM操作包括设置和获取。 修改元素上CSS属性的值时,就是在设置(更新)DOM。 相反,当您向DOM查询元素CSS属性的当前值时,您正在获取(查询)。 这些DOM操作会产生性能开销。 设置DOM后,浏览器必须计算更改的效果。 毕竟,当您更改一个元素的宽度时,它会触发连锁React,从而导致其父元素,同级元素和子元素的宽度发生变化。
这种由交替的DOM集和获取导致的帧速率降低现象被称为“布局抖动”。
浏览器已经过优化,可以快速执行DOM布局的重新计算,但是当动画循环并发运行时,每毫秒都是宝贵的时间,而DOM操作是触发浏览器开销的最快方法,其触发时间在几毫秒的范围内(而大多数JavaScript操作在一小部分内完成一毫秒)。 为了说明动画循环对时间的敏感程度,为了达到每秒60帧(眼睛感知黄油平滑运动的速率),动画循环中的每个刻度必须在16ms(1s / 60 = 16.666ms)之内完成。
速度要竭尽全力,以最大程度地减少布局抖动和DOM操作。
首先,作为Velocity的唯一开发人员,我花时间在Velocity的整个源代码中放置注释,以突出显示操纵DOM的所有有害代码行。 简而言之,我在适当的地方撒上/* GET */
和/* SET */
。 坚持这种做法,使我能够快速关注我的代码,以确保新功能或错误修复不会引起布局混乱。 我遵循代码路径,看看是否/* GET */
后跟/* SET */
。 如果是这样,我要么重新设计批处理SET和GET的路径(以最大程度地减少颠簸的发生),要么避免完全实现该功能。
其次,Velocity会尽可能对缓存的值进行操作,这样就不必在每个动画开始时都重新查询DOM。 例如,Velocity检测何时将多个动画链接在一起,并重用先前的Velocity调用的动画结束值作为后续调用的开始值。 这是一个微妙的过程,因为必须不惜一切代价避免对过时的值进行操作,否则动画可能会崩溃。 Velocity通过标记每个Velocity发起的动画调用来解决这种不确定性,然后在检测到链中的先前调用不是由Velocity发起时避免随后进行值缓存(例如jQuery的$.queue()
或$.fade()
函数在Velocity调用之间注入)。
Velocity使用的第三个也是最后一个主要的DOM最小化技术是其“真空”方法转换单位转换率。 单位转换逻辑是确定以像素为单位的百分之一的代码。 在将元素的宽度设置为例如“ + 25%”的动画时,这是必要的-动画引擎必须确定该值的像素单位,以便可以使用相同单位类型的两个值执行增量数学运算。 为什么特别是像素? 因为浏览器在查询时返回CSS属性值(以像素为单位),而与用于设置属性的单位类型无关。
单位转换过程需要将目标元素的宽度和高度临时设置为1%,然后计算随后的DOM查询针对该元素的尺寸返回的内容。 返回的值(以像素为单位)将提供介于1%和像素之间的比率。
Velocity在此单位转换过程中进行了三个关键的优化:首先,它在通过测试的元素之间缓存单位转换比率,以确定它们是否共享相同的比率(即,它们具有相同的父元素和相同CSS位置值)。 当一组元素同时被动画化时,这一点至关重要。
其次,Velocity在不需要时完全跳过单位转换。 例如,当属性的起始值为0时,每种单位类型的零都为零-无需转换。
第三,Velocity唯一地选择在DOM树修改上进行布局调整。 前一种技术通过将动画元素暂时放置在虚拟CSS属性“ vacuum”中而产生了数量不等的交替DOM获取和设置,在那里剥夺了CSS属性会影响尺寸计算(例如,框大小,溢出)。 属性剥离,然后是临时值的设置和获取,再接着是将元素重置为其初始值,需要进行几轮布局调整。
但是,我在Velocity的开发过程中发现的是,布局修改比迄今为止使用的技术更有效:通过克隆动画元素将DOM树连根拔起,将克隆插入到原始对象旁边,然后在克隆,然后将其完全删除。 此方法是理想的,因为它避免了创建CSS真空的非平凡过程,但是它导致了DOM树的重组(通过插入和删除元素来影响其层次结构),最终导致浏览器的开销比交替显示更大CSS属性值可以。 (我使用jsPerf.com在浏览器和设备上确认了这些结果;正如其维护者会告诉您的,这是jsPerf变得异常强大的地方-当您需要比较许多环境中的真实瓶颈情况时。)
放在一起
那么,您可以利用Velocity.js的所有潜在功能做什么呢?
- 你可以设计排版激烈动画,竞争者影片信用序列(桌面只): 演示#1通过@rachsmithtweets , 演示#2的@legomushroom 。
- 您可以将一系列标准div元素转换为3D粒子演示 (所有设备)。
这两个演示都完全在DOM中运行。 没有WebGL。 没有画布。
就日常的网页设计而言,可以在Everlane.com上找到Velocity的UI性能的最新著名示例 。 浏览; 体验令人难以置信的流畅和响应能力。
如您所见,DOM和JavaScript非常快。 您只需要考虑性能最佳实践。
查看以下资源以了解更多信息。
网络性能资源
翻译自: https://www.sitepoint.com/incredibly-fast-ui-animation-using-velocity-js/
velocity.js