Multiple requestAnimationFrame performance
JavascriptJqueryPerformanceAnimationRequestanimationframeJavascript Problem Overview
If I’m doing multiple animations, is it OK performance-wise to add multiple requestAnimationFrame
callbacks? F.ex:
function anim1() {
// animate element 1
}
function anim2() {
// animate element 2
}
function anim3() {
// animate element 3
}
requestAnimationFrame(anim1);
requestAnimationFrame(anim2);
requestAnimationFrame(anim3);
Or is it proven worse than using a single callback:
(function anim() {
requestAnimationFrame(anim);
anim1();
anim2();
anim3();
}());
I’m asking because I don’t really know what is going on behind the scenes, is requestAnimationFrame
queuing callbacks when you call it multiple times?
Javascript Solutions
Solution 1 - Javascript
I don't think any of these answers really explained what I was looking for: "do n calls to requestAnimationFrame" get debounced (i.e. dequeued 1 per frame) or all get invoked in the next frame.
> When callbacks queued by requestAnimationFrame() begin to fire multiple callbacks in a single frame (mdn)
This suggests the latter, multiple callbacks can be invoked in the same frame.
I confirmed with the following test. A 60 hz refresh rate translates to a 17ms period. If it were the former, no 2 timestamps would be within 17ms of each other, but that was not the case.
let sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
let update = async timestamp => {
console.log('update called', timestamp)
await sleep(10);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
requestAnimationFrame(update);
Solution 2 - Javascript
You should be using only one requestAnimationFrame
call as calls to requestAnimationFrame
do stack. The single callback version is thus more performant.
Solution 3 - Javascript
Someone benchmarked this. Let's talk...
https://jsperf.com/single-raf-draw-calls-vs-multiple-raf-draw-calls
I looked at the performance comparison (you should too). You're welcome to disagree. These are drawing primitives on a canvas element.
function timeStamp() {
return window.performance && window.performance.now ? window.performance.now() : new Date().getTime();
}
function frame() {
drawCircle();
drawLines();
drawRect();
}
function render() {
if (timeStamp() >= (time || timeStamp())) {
time = timeStamp() + delayDraw;
frame();
}
requestAnimationFrame(render);
}
function render1() {
if (timeStamp() >= (time || timeStamp())) {
time = timeStamp() + delayDraw;
drawCircle();
}
requestAnimationFrame(render1);
}
function render2() {
if (timeStamp() >= (time || timeStamp())) {
time = timeStamp() + delayDraw;
drawRect();
}
requestAnimationFrame(render2);
}
function render3() {
if (timeStamp() >= (time || timeStamp())) {
time = timeStamp() + delayDraw;
drawLines();
}
requestAnimationFrame(render3);
}
I think this code is really benchmarking 7 calls to timestamp() vs 2 calls to timestamp(). Look at the difference between Chrome 46 and 47.
- Chrome 46: 12k/sec (one call) vs 12k/sec (3 calls)
- Chrome 47: 270k/sec (one call) vs 810k/sec (3 calls)
I think this is so well optimized that it doesn't make a difference. This is just measuring noise at this point.
My takeaway is this doesn't need to be hand-optimized for my application.
If you're worried about performance look at the difference between Chrome 59 (1.8m ops/sec) vs Chrome 71 (506k ops/sec).
Solution 4 - Javascript
The requestAnimationFrame binds a function call and returns the frameID. Requesting multiple frames is NOT the same like adding multiple event listeners to an event- each of your functions is called in another frame. So if you continuously (each function recalls itself recursively) request several frames you're loosing the benefit that all updates are rendered within one frame. So even if there is a high framerate animations may not look that smooth.
But: you can only use cancelAnimationFrame(frameID) for all methods and may need some extra code to cancel single animations