1

Given the following psudo-code (which is taken from my remote camera robot project)

[event handler](when event happens) {
   [do some startup and init code]
   start_everything_going();
}

// This block does something that will interact with the browser every 1/60 second.
def do_something() {
    [code that does something goes here]
   requestAnimationFrame(do_something);
}

def start_everything_going() {
    requestAnimationFrame(do_something);
}

The way this works using requestAnimationFrame is that the event handler triggers, (say when a joystick is attached or activated), and after some setup or configuration code is run, it calls the initial function to begin the cyclical animation - start_everything_going().

Since requestAnimationFrame runs once and once only when called, it has to be repeatedly called to create a continuous effect.

The canonical method - and the one used in every example I have seen - is that the first invocation is done by a wrapper function called (eventually) by the event handler that triggers it, or something the event handler launches.

In order to repeatedly call requestAnimationFrame, the actual animating function calls requestAnimationFrame, with itself as the argument, as the last thing before exiting.

As far as I know, this is recursion, and is called recursion in all the docs about requestAnimationFrame I've seen. (i.e. MDN, Stack Overflow, (etc.).)

As I remember, a recursive call to a function creates yet another instance of the function, (leaving the original instance suspended in time somewhere), repeating the steps needed to do something. And this continues forever, creating additional instances of itself until, (eventually), some ending condition is reached.

Since, in this case, the called function never returns, there is no way to “unwind” the recursion. And, as far as I know, this will continue until either Hell freezes solid or all available computer resources have been exhausted.

Since this animation refreshes itself every 1/60th second, and can (theoretically) run for hours and hours and hours and hours and hours, what keeps this from folding up like a house of cards and crashing the system due to resource exhaustion?

Jim JR Harris
  • 413
  • 1
  • 6
  • 15
  • `requestAnimationFrame` is *asynchronous*. It returns before it (later) calls the callback function. – Bergi Jun 18 '20 at 21:10

1 Answers1

1

It's not actually a recursive call in the function-stack sense, only in the broad sense.

When you call requestAnimationFrame(callbackFunction), the requestAnimationFrame function schedules the callback function with the browser to be called on the browser's next frame. Then requestAnimationFrame returns and gets popped off the stack, the function stack finishes executing until every other function returns and gets popped off the stack, and control is handed back to the browser.

In other words, the stack resolves fully, then on the next frame, the browser spins up the function stack again by executing callbackFunction.

A function calling itself is classic recursion, which is very common in programming when a complex algorithm needs to repeat itself, (like calculating a mathematical series or many digits of an irrational number like π).

There's an important distinction here. requestAnimationFrame doesn't actually call itself directly. callbackFunction calls requestAnimatonFrame, which then flags the browser to call callbackFunction on the next frame. Then requestAnimationFrame returns, and the function stack continues to resolve completely.

Since, in this case, the called function never returns, there is no way to “unwind” the recursion.

Technically the called function returns every frame, then the browser executes it again the next frame.

Maximillian Laumeister
  • 19,884
  • 8
  • 59
  • 78
  • 1
    Thanks for a very excellent explanation of the process. I wonder why this kind of explanation is so difficult to find? I searched everywhere without seeing anything like this. – Jim JR Harris Jan 05 '22 at 14:08