What is going on that allows the rest of the loop to execute, and then for requestAnimationFrame to execute next frame?
I am misunderstanding how this method works, and can't see a clear explanation anywhere. I tried reading the timing specification here http://www.w3.org/TR/animation-timing/ but I couldn't make out how it worked.
Edit:
For example, this code is taken from the threejs documentation.
var render = function () {
requestAnimationFrame(render);
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
};
Please let me know if I am completely off-base; I haven't used the animation stuff before. An example I saw for using requestAnimationFrame
is:
(function animloop(){
requestAnimFrame(animloop);
render();
})();
Are you wondering why animloop
as it is passed into requestAnimFrame
doesn't cause an infinite loop when it is subsequently called?
This is because this function isn't truly recursive. You might be thinking that animloop
is immediately called when you call requestAnimFrame
. Not so! requestAnimFrame
is asynchronous. So the statements are executed in the order that you see. What this means is that the main thread does not wait for the call to requestAnimFrame
to return, before the call to render()
. So render()
is called almost immediately. However the callback (which in this case is animloop
) is not called immediately. It may be called at some point in the future when you have already exited from the first call to animloop
. This new call to animloop
has its own context and stack since it hasn't been actually called from within the execution context of the first animloop
call. This is why you don't end up with infinite recursion and a stack overflow.
This is what happens:
you declare a function definition, call requestAnimationFrame
function.
Which schedule your function to be called and executed again when the time is right, which is the Next frame that is usually after 16ms. Also, this scheduling is async. It won't stop the execution of code below it. So it's not like code below this line won't work until 16ms has passed.
However, in most cases function executes within 3-4 ms.
But if function were to take longer to finish the next frame would be delayed thus not executing the scheduled task which is to call the same function over again.
In a sense animation is infinite loop. Which requestAnimationFrame aims to be. However, this nonblocking infinite loop is limited by frames/fps.
For the same reason that scheduling a callback with setTimeout
in a loop wont cause infinite recursion, it schedules the next call on the JS event loop instead of executing it immediately.
The call is not made in the current context, so it's technically not recursion in the strict sense of the word, and it wont cause stack limit exceeded errors.
(source: dartlang.org)
This diagram is for Dart, but the concept is the same in JS. If you're interested in reading more about event loops, scheduling timers, and the difference between microtasks and macrotasks, check out this question.