拥有更好性能的requesAnimationFrame(Better Performance with requestAnimationFrame)

介绍:

  这篇文章讨论的是你可以(也应该)学习通过使用requestAnimationFrame API,而不是使用之前的setInterval/setTimeout方法,来提高动画的性能;如何使用requestAnimationFrame。当然,我们将会为你展示完善的代码example of requestAnimationFrame in action.

  requestAnimationFrame 已经被现在所以的主流浏览器支持了,尽管有一些浏览器需要加前缀。Erik Moller已经写了一个可以在所有浏览器均支持requestAnimationFrame的polyfill。 我们等会会更细致的讨论的。让我们从头开始讲吧。。。

 不太好的老方法

  为了能展示出requestAnimationFrame是多么好,我们首先必须先看看我们用来做动画的不太好的老方法。我敢肯定我不需要告诉你早在Mozilla在实行第一次mozRequestAnimationFrame实验时,你可能已经用setTimeout和setInterval创建动画。我假定你已经熟悉这两个方法了,所以我就不深入讲解了, 如果你想深入了解的话,这里有篇John Resig深度讲解的文章:how JavaScript timers work

  我不想对这些老方法不屑一顾,不幸的是他们确实有一些缺点。 首先,在切换到一个不同的标签时,甚至当相应页面最小化时,JavaScript计时器仍将继续工作。造成的后果就是,浏览器继续运行无形的动画,这导致了动画过度绘制,浪费 CPU 周期以及消耗额外的电能等问题。 在移动设备上,这会是特别糟糕的问题。

  第二,计时器不仅会继续运行看不见的动画,而且当时间到了的时候他们总是还要排队等待他们的回调函数。让我来解释下为什么这种情况有时会带来问题 -- 就是说你没有很好的完成你的工作,因为某些原因回调函数完成所需要的时间比你设置计时器的时间要长。一旦计时器的时间到了,他们又将排队到另外一个回调函数。尽管前一个还没有完成运行。随着时间的推移,这个过程一直重复着,你可以迅速排队到几乎无数的计时器, 这将导致浏览器停止运行。 图片1具体说明了这个问题。

图片1:如果回调函数执行的时间比定时器还要长,大量排队的回调函数将会阻塞浏览器

  但是即使你的回调函数花费的时间不超过计时器,在这种情况下,setTimeout和setInterval仍然不是最佳的选择。他们都只能以固定的速率重新绘制动画,因此为了确保动画平滑,我们往往宁可谨慎来选择一个比显示刷新略高的频率。然而,由于一些帧在显示刷新率准备绘制动画之前被绘制了,因此就被丢弃,这就导致了过度绘制的问题。图片2具体说明了这个问题.

图片2:跳帧可以导致更高的CPU使用率和电池消耗,甚至有时不稳定的动画。

  当这些方法用于实现循环动画,这些缺点更加危险。在这样的场景中,例如在游戏中或者像我的潮人狗的疯狂的实验中,循环动画导致无休止的的排队等待新的回调函数。如果你想更多的了解网络循环动画的历史。当使用setTimeout和setInterval时,循环动画的行为是什么,以及requestAnimationFrame是怎样改变我们的代码的。我推荐你阅读Nicholas Zakas写的 Better JavaScript animations with requestAnimationFrame,他在这面讨论的很深入。

 介绍requestAnimationFrame

  requestAnimationFrame正是你所期望的一款API:它将调度动画绘制的职责直接传递给浏览器。浏览器可以做的更好,因为,它知道浏览器的机制是什么!

  requestAnimationFrame是W3CTiming control for script-based animations API的一部分。

  requestAnimationFrame是做什么的

  浏览器非常了解例如tab和窗口状态,网页的哪部分是可见的或者不可见,浏览器何时准备绘制,以及哪些其他动画也在运行还有哪些动画是可见的。我们之前讨论过通过让浏览器控制动画,允许浏览器使用信息来优化动画调度,requestAnimationFrame使用JavaScript定时器追踪问题。因此,requestAnimationFrame的工作流程如下:

  • 首先,RAF(Request Animation Frame)只绘制哪些对用户可见的动画。这意味着RAF会暂停那些隐藏的tabs、最小化的窗口或者隐藏的部分页面的动画,直到这些窗口或页面可见,这样就不会浪费CPU和电池的寿命。
  • 其次,帧只会在当浏览器准备绘制并且没有其他的帧等待被绘制时才会绘制。这意味着这些情况是不可能发生的:使用requestAnimationFrame绘制动画需要排队超过一个回调函数或者使浏览器瘫痪。
  • 第三,帧只会在当浏览器准备绘制并且没有其他的帧等待被绘制时才会绘制,没有不必要的帧绘制。所以动画更流畅了,CPU和电池的使用进一步得到优化。

  我刚刚只是说没有额外的回调函数队列,直到当前动画完成绘制并且已经渲染了。然而,如果每次回调不止一次的调用requestAnimationFrame()将有一个回调队列,所以将会有额外的回调函数。

  同时,浏览器在一个回流和重绘周期可以有几个动画发生在同一个页面。

 requestAnimationFrame不做什么

  requestAnimationFrame不做:

  • 设置连续的动画; RAF只会安排一个更新,这个更新通过一个id number识别,返回特定的请求。如果需要后续动画帧,requestAnimationFrame将在回调函数再次被调用。如果需要停止动画,你可以使用cancelAnimationFrame(id).
  • 确保当RAF 绘制时,只有在需要时才会绘制。
  • 确保动画的同步性。例如,你同时开始两个动画,但是其中一个动画在可见区域,另一个不在,可见的动画会一直绘制而另一个则不会;当不可见的再次可见时,他们有可能不同步了。如果你需要确保他们的同步性,当写代码时,就需要注意了。可以通过确保所有需要同步的动画的状态是由一个不受可见性影响的参数决定的(例如,像动画组的起始时间。)这与依据每个动画的前一个帧相反。
  • 绘制直到回调函数执行完成。即使你试图触发一个回流中间回调,在正常情况下,通过任何能够触发一个回流方法、重绘。例如,像getComputedStyle().

 怎样使用requestAnimationFrame

  RAF现在被所有现代浏览器所支持,但是有些浏览器需要加前缀。截止写这篇文章为止,加前缀或不加前缀的情况如下:

  • Opera: 不加前缀 opera15+
  • Chrome:版本24之后不加前缀
  • Safari:加前缀
  • Firefox: 加前缀,尽管版本23之后不加前缀
  • IE:IE10之后不加前缀

  然而,为了使你的代码在所有环节下都能兼容,你应该使用Erik Moller’s polyfill, 它提供了强大的跨浏览器支持,在Paul Irish’s fantastic original groundwork on the subject的基础上进行优化的。

  下面就是我们青蛙动画演示的简单代码:

var requestId = 0;
var animationStartTime = 0;

function animate(time) {
    var frog = document.getElementById("animated");
    frog.style.left = (50 + (time - animationStartTime)/10 % 300) + "px";
    frog.style.top = (185 - 10 * ((time - animationStartTime)/100 % 10) + ((time - animationStartTime)/100 % 10) * ((time - animationStartTime)/100 % 10) ) + "px";
    var t = (time - animationStartTime)/10 % 100;
    frog.style.backgroundPosition = - Math.floor(t / (100/2)) * 60+ "px";
    requestId = window.requestAnimationFrame(animate);
}
function start() {
    animationStartTime = window.performance.now();
    requestId = window.requestAnimationFrame(animate);
}
function stop() {
    if (requestId)
    window.cancelAnimationFrame(requestId);
    requestId = 0;
}

  requestAnimationFrame是一种方法,它会向浏览器发出信号表明一个基于脚本的动画需要通过将回调排入到动画帧请求回调列表队列中来重新取样。它拥有一张关于回调函数id的列表,这些回调函数正在等待执行。调用requestAnimationFrame返回id(requestId),id标识已经插入队列的回调。这个id可以之后用于取消回调,使用cancelAnimationFrame(id)来取消。

  requestAnimationFrame方法将参数昨晚回调,回调函数需要来执行去绘制一个新的动画帧(动画).回调,反过来,本身就是一个函数,接受动画更新时的时间戳作为参数(时间)。

  时间戳是调用优化性能的now方法的结果。你需要确定任何其他你想要比较的时间测量也是DOMHighResTimeStamp -- 在上面的例子中,我们调用window.performance.now和用animationStartTime变量存储结果。之后在动画函数(animate)中我们比较每一帧的开始时间和当前时间来计算青蛙在每种情况下的位置。

  当编写动画时,万一你遇到旧教程,注意animationStartTime属性已经创建了,但是现在已经弃用了,所以你自己必须跟踪开始时间像我上面所示。

  可以访问我的requestAnimationFrame demo

 总结

  在这篇文章中我们讨论了requestAnimationFrame是怎样提高JavaScript动画性能的,你怎样使用来兼容所有浏览器。我希望这篇文章能激励你尝试更多更酷的动画效果--你可以更新任何用老方法实现的就动画代码。

外文翻译链接:Better Performance With requestAnimationFrame

时间: 2024-08-07 02:09:55

拥有更好性能的requesAnimationFrame(Better Performance with requestAnimationFrame)的相关文章

Windows性能优化关键点-Windows Performance tuning important settings

最近重装了windows8系统,发现性能差得很,原不如官方说的比win7好很多的说法.经过几个关键配置的调整,终于找回电脑原来的风采. 下面总结一下,希望对大家有帮助: 1. 检查windows服务,把不需要的服务关闭 其中最容易被遗忘的时windows media network service,不需要网络多媒体共享的朋友最好关掉它,它扫描媒体可是很迟硬盘的. 2. 看一下电源选项,是否已经配置成性能使用性能最优选项(本人使用的时英文版WINDOWS8,WINDOWS7的配置类似,到更改计划里

Ab3d.PowerToys 3D辅助库更好性能的3Dlines实现

Ab3d.PowerToys是与WPF 3D一起使用的辅助库. 该库的主要部分是: Cameras (SceneCamera, FirstPersonCamera, ThirdPersonCamera, 等) Camera Controllers (MouseCameraController, CameraControlPanel) 3D Models and Visuals (Sphere, Box, Cylinder,等) 3D Lines Event Manager 3D (简化了3D对象

Android Lollipop拥有更先进的通知中心

Android L带来了全新的"MaterialDesign"设计语言,看上去极具个性.主打干净排版和简单布局的设计风格,同时融入了丰富的色彩,具有更强的指向性.新增了动画触觉反馈功能,当你按下屏幕上的一个虚拟按钮,会得到动画式的反馈效果. 界面所有设计元素都经过了修改,甚至导航键都经过了重新设计了,新的界面开始扁平化并更加丰富多彩.除了界面风格设计的改变之外,增加"最近应用界面",它借鉴了Chrome浏览器的理念,采用单独的标签展示方式. CPU与GPU性能全面提

ASP.NET Core 3.0:将会拥有更少的依赖

在ASP.NET Core项目中,我们使用一个叫做Microsoft.AspNetCore.App的综合包.它也被称为ASP.NET Core Shared Framework,在ASP.NET Core Shared Framework之中包含了很多依赖项,它能满足一般应用的需求.但是如果你查看它的依赖项,在ASP.NET Core3.0中它的需求在似乎变得宽松了. 当前版本的Microsoft.AspNetCore.App明确列出了150个依赖项,而7个月前的版本只需要144个.在这些包中,

更新Edge引擎:更好性能和HTML5兼容性

Edge是微软用来在浏览器市场重塑自我,并与Google Chrome和Mozilla Firefox展开更直接的竞争的“大杀器”.尽管在刚发布的时候,其某些方面的功能仍明显落后于其竞争对手,但该公司正在通过更频繁的更新和功能改进来 证明自己.今天,微软为新浏览器带来了首个平台更新,它就是EdgeHTML 13. 尽管Insider测试者们已经用上了几个月,但大量普通用户还是在Windows 10 TH2(11月更新)之后才注意到这个变化. 其最大的一项改进,来自于新渲染引擎对于标准的更佳支持.

Yahoo 开源的 MySQL 性能分析工具(MySQL Performance Analyzer)

原文地址:https://github.com/yahoo/mysql_perf_analyzer MySQL Performance Analyzer is an open source project for MySQL performance monitoring and analysis. This repository includes two sub projects: Java web application project myperf Java web server jetty

MyEclipse中更好性能的过滤数据库模式

当在数据库浏览器中打开一个数据库连接时,默认的操作是获取每个数据库模式的相关信息.数据库资源管理器允许您通过数据库连接选择过滤器来管理这些模式,应用模式过滤器的主要原因是优化.在这个教程中,您将学习到: 过滤数据库模式 持续时间:10分钟 没有MyEclipse?立即下载 过滤数据库模式具有以下优点: 打开一个数据库连接时提高连接性能 限制数据库浏览器呈现的信息量 为支持SQL代码完成功能新增元数据检索性能 模式过滤器被创建为一个连接配置文件定义的一部分,同时使用连接配置文件向导来对其进行管理.

手机控必备网站,让自己拥有更好的智能手机

手机成为人们日常生活标配后,无论年幼年长还是年轻群体,都将业余时间给了手机,而移动互联网不但满足了我们的需要,还方便了我们的生活,但如果没有一部好的手机,我们分分钟都有想砸手机的暴躁心情,可想而知,手机对于我们生活有何影响. 而机不离手的人通常也会被称为"手机控"."低头族",基本睡醒一睁眼拿起的东西就是手机,睡前最慢放下的也是手机,于是,现在人们对于手机的功能及质量要求越来越高:手机厂商也看准用户这一需求,扛着高配的旗号标配高价,再标榜着各种新科技体验,手机控对这

SparseArray<E>来替代HashMap,获取更好性能

今天看到一个SparseArray的类,查下相关资料进行总结. SparseArray指的是稀疏数组(Sparse array),所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用.因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以采用一种压缩的方式来表示稀疏数组的内容. 从构造方法我们可以看出,它和一般的List一样,可以预先设置容器大小,默认的大小是10,是Android提供的一个工具类 单纯从字面上来理解,SparseAr