There used to be just one way to do a timed loop in JavaScript: setInterval()
. If you needed to repeat something pretty fast (but not as-fast-as-absolutely-possible like a for
loop), you’d use that. For the purposes of animation, the goal is sixty “frames” per second to appear smooth, so you’d run a loop like this:
setInterval(function() {
// animiate something
}, 1000/60);
There is a better alternative to this now. Paul Irish introduced requestAnimationFrame
over two years ago. I don’t have a whole lot to add to it, I just had never actually used it before and now I have so I thought I’d help spread the word and write about its basic usage.
Why better?
As Paul explained:
- The browser can optimize it, so animations will be smoother
- Animations in inactive tabs will stop, allowing the CPU to chill
- More battery-friendly
The Simplest Possible Example
function repeatOften() {
// Do whatever
requestAnimationFrame(repeatOften);
}
requestAnimationFrame(repeatOften);
Call it once to kick it off, and your function recursively calls itself.
Start and Stop
requestAnimationFrame
returns an ID you can use to cancel it, just like setTimeout
or setInterval
does. jQuery used here only to demonstrate a simple animation and bind events.
var globalID;
function repeatOften() {
$("<div />").appendTo("body");
globalID = requestAnimationFrame(repeatOften);
}
$("#start").on("click", function() {
globalID = requestAnimationFrame(repeatOften);
});
$("#stop").on("click", function() {
cancelAnimationFrame(globalID);
});
Example of this:
Check out this Pen!
Browser Support
See the Can I Use… tables.
The only notable problems are IE 9-, iOS 5-, and Android. But not actually a problem, because:
Polyfill
Like many fancy web features, it’s nice to use it when available and fallback to something that works when you can’t. Probably best just to refer to this Gist. Literally just include that chunk anywhere before you use requestAnimationFrame
or cancelAnimationFrame
.
Using this, you’ll be able to use requestAnimationFrame
in literally any browser.
Slightly More Complex Example
I learned about this while making a dumb little demo to learn canvas better:
See the Pen Super Simple requestAnimationFrame Thing by Chris Coyier (@chriscoyier) on CodePen.
What would actually be more complex is several animations running at once using this (that still falls back OK). Feel free to link some of that goodness up in the comments if you know of examples.
You can make your “Simplest possible example” even simpler :)
Yes, for the sake of simplicity it works, but I wouldn’t recommend to start an animation like that, because it would be rendered in the exact same moment it’s called and not when the browser actually is free, so it misses the point of requestAnimationFrame.
Or even more simple:
On the first example, click start more than once. :P
Oh, yeah and we still have to use vendorprefixes for it, but it is a great method. The web is in continous evolution…
The polyfill mentioned above handles that, and a few more little things to make sure it all works perfect (like falling back to setTimeout and handling cancellations).
Here is a fork of the first example but have added some code so that if you click buttons more than once it doesn’t break.
http://cdpn.io/cCoFf
Also just realised this demo can be a great way of playing at making patterns out css nth type selectors.
That’s really nice. I wonder if an image can be in-scripted in it.
Sure it could be if you work out the pattern of nth squares.
First of all thank you for this really great inovation ! I have some questions that Why request Animation Frame won’t let you alter frame rate? Why is 60fps the default, and why can’t this be changed? Or can it?
You can by wrapping it in a setTimeout! There is more info in this article: http://creativejs.com/resources/requestanimationframe/
I read a tut on paulirish’s blog and he suggests you move the call-yourself of your function to the start of the function to get closer to 60fps when on the setTimeout fallback
http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
I’m having trouble with trying to use an animation function that’s a class method. It needs to access other properties and methods from the class, but the context I’m getting is the Window object.
I’ve tried using
call
andbind
, but haven’t gotten that to work. Any ideas?guessing it’s no longer relevant, but either of these should work
var animId = requestAnimationFrame(o.anim.bind(o)); //built-in bind
or
var animId = requestAnimationFrame(function(){o.anim()}); //manual bind
The start-stop demo works awfully in Safari (v5.1.7), poorly in FF(v26) and Opera (v17.0) in my tests.
It works good only on Chrome(30) and IE(v10).
SO, I think it is a waste of time to implement it . Just stick to setInterval function, at steps of 16.67ms (60hz).
Unfortunately the morons behind the browser development and standardization are still left in the technology of the 70’s or earlier when genlock was introduced to synchronize the video cameras with the VCRs and their unbelievable idiocy and sloppiness still affect all of us.
Hi Chris, Great lecture about requestanimationframe, i need to know, How to control speed using this function?
I expect the best option is to base your speed off the timestamp parameter it passes into the callback
Alternately you could use an external setInterval to move things around & just draw them in requestAnimationFrame
I don’t think you can change how often requestAnimationFrame fires, though perhaps using a monitor with a different frame rate might work but I think 60Hz is universal
You said “recursively calls itself”… But, be careful, because this isn’t recursion as people usually think of it (with the side effects of stack space, etc).