Skip to content

Home

Run a callback on each animation frame with JavaScript

Using animation frames is a common technique in web development to create smooth animations. The Window.requestAnimationFrame() method is used to invoke a callback before the next repaint of the browser window.

We can leverage this knowledge to create a function that runs a callback on each animation frame. This can be useful for creating custom animations or for running a function at a high frequency.

In order to achieve this, we can use recursion to keep invoking Window.requestAnimationFrame() as long as a flag is set to true. We can also provide methods to start and stop the recording of animation frames. Additionally, we can control the start of the recording by passing an optional argument.

In order to track the state of the recording, we can use a variable, running, and a reference to the requestAnimationFrame function, raf. We can then use the start and stop methods to control the recording.

Starting with out run function, we use recursion to keep invoking Window.requestAnimationFrame() as long as running is true. We call the provided callback and, if running is still true, we call run again.

Our start function will check if the recording is already running and return if it is. If it isn't, we set running to true and call the run function.

Our stop function will simply check if the recording is already stopped and return if it is. If it is running, we set running to false and cancel the animation frame using cancelAnimationFrame().

Finally, if the autoStart argument is true, we call start when the function is invoked. If it is set to false, we require the user to call start manually.

const recordAnimationFrames = (callback, autoStart = true) => {
  let running = false, raf;

  const stop = () => {
    if (!running) return;
    running = false;
    cancelAnimationFrame(raf);
  };

  const start = () => {
    if (running) return;
    running = true;
    run();
  };

  const run = () => {
    raf = requestAnimationFrame(() => {
      callback();
      if (running) run();
    });
  };

  if (autoStart) start();

  return { start, stop };
};

const cb = () => console.log('Animation frame fired');

const recorder = recordAnimationFrames(cb);
// Logs 'Animation frame fired' on each animation frame
recorder.stop();
// Stops logging
recorder.start();
// Starts again

const recorder2 = recordAnimationFrames(cb, false);
// `start` needs to be explicitly called to begin recording frames

More like this

Start typing a keyphrase to see matching snippets.