What is raf-schd?
The raf-schd package is a small utility that creates a throttled function that only invokes the provided function at most once per animation frame. It's useful for optimizing performance by reducing the number of times a function is called during rapid events such as scrolling, resizing, or animations.
What are raf-schd's main functionalities?
Throttling function calls
This code sample demonstrates how to create a throttled version of an expensive function that is called at most once per animation frame. This is useful for attaching to events that fire rapidly, such as 'resize' or 'scroll' events.
import schedule from 'raf-schd';
const expensiveFunction = () => {
// Expensive operation
};
const throttledFunction = schedule(expensiveFunction);
window.addEventListener('resize', throttledFunction);
window.addEventListener('scroll', throttledFunction);
Other packages similar to raf-schd
throttle-debounce
The throttle-debounce package provides throttle and debounce functions that can be used to rate-limit functions. It is similar to raf-schd in that it helps in optimizing function execution frequency, but it does not specifically tie the throttling to requestAnimationFrame.
lodash.throttle
lodash.throttle is a function from the popular Lodash library that throttles a function call. It is similar to raf-schd but offers more customization options, such as leading and trailing invocation control. Unlike raf-schd, it does not use requestAnimationFrame and allows setting a custom delay.
frame-throttle
frame-throttle is a package that provides a similar functionality to raf-schd by throttling function calls to the next animation frame. It is a direct alternative to raf-schd, with a similar API and use case.
raf-schd
A scheduler based on requestAnimationFrame
. It throttles calls to a function and only invokes it with the latest argument in the frame period.
import rafSchedule from 'raf-schd';
const expensiveFn = (arg) => {
console.log(arg);
}
const schedule = rafSchedule(expensiveFn);
schedule('foo');
schedule('bar');
schedule('baz');
Why?
raf-schd
supports the use case where you only want to perform an action in an animation frame with the latest value. This an extremely useful performance optmisation.
Without raf-schd
Optimised scroll listener example taken from MDN
var last_known_scroll_position = 0;
var ticking = false;
function doSomething(scroll_pos) {
}
window.addEventListener('scroll', function(e) {
last_known_scroll_position = window.scrollY;
if (!ticking) {
window.requestAnimationFrame(function() {
doSomething(last_known_scroll_position);
ticking = false;
});
}
ticking = true;
});
With raf-schd
import rafSchedule from 'raf-schd';
function doSomething(scroll_pos) {
}
const schedule = rafSchedule(doSomething);
window.addEventListener('scroll', function() {
schedule(window.scrollY);
});
Types
rafSchduler
type rafSchedule = (fn: Function) => ResultFn
type ResultFn = (...arg: any[]) => number;
At the top level raf-schd
accepts any function a returns a new ResultFn
(a function that wraps your original function). When executed, the ResultFn
returns a number
. This number is the animation frame id. You can use this frame id to cancel the scheduled frame using cancelAnimationFrame(id)
;
The ResultFn
will execute your function with the latest arguments provided to it on the next animation frame.
Throttled with latest argument
import rafSchedule from 'raf-schd';
const doSomething = () => {...};
const schedule = rafSchedule(doSomething);
schedule(1, 2);
schedule(3, 4);
schedule(5, 6);
Cancelling a frame
const scheduled = rafSchedule(doSomething);
const frameId = schedule('foo');
cancelAnimationFrame(frameId);
Is this a throttle
, debounce
or something else?
raf-schd
is closer to throttle
than it is debounce
. It is not like debounce
because it does not wait for a period of quiet before firing the function.
Lets take a look at the characteristics of this library:
Similiarities to throttle
- It batches multiple calls into a single event
- It only executes the wrapped function with the latest argument
- It will not execute anything if the function is not invoked
- One invokation of a scheduled function always results in at least one function call, unless canceled. This is
throttle
with tail calls enabled.
Differences to throttle
- Rather than throttling based on time (such as
200ms
, this library throttles based on requestAnimationFrame
. This allows the browser to control how many frames to provide per second to optimise rendering. - Individual frames of
raf-schd
can be canceled using cancelAnimationFrame
as it returns the frame id.
Testing your code
If you want to really ensure that your code is working how you intend it to - use raf-stub
to test your animation frame logic.
Installation
yarn add raf-schd
npm install raf-schd --save
Module usage
ES6 module
import rafSchedule from 'raf-schd';
CommonJS
If you are in a CommonJS environment (eg Node), then you will need add .default
to your import:
const rafSchedule = require('raf-schd').default;