A tiny utility that makes it easy to chain (and cancel) multiple DOM timers with a simple unified API:
requestAnimationFrame -> "raf"
requestIdleCallback -> "ric"
setTimeout -> ms
import waitForTimers from 'wait-for-timers';
const cancel = waitForTimers([1000, 'ric', 'raf'], () => {
// Wait a second, then for browser to be idle, then
// for frame to be ready, then do something...
});
Install via npm or yarn:
npm install wait-for-timers
Avoid deep nesting:
// Before
setTimeout(() => {
requestIdleCallback(() => {
requestAnimationFrame(() => {
// Do something
});
});
}, 3000);
// After
waitForTimers([3000, 'ric', 'raf'], () => {
// Do something
});
This is where the abstraction really comes in handy:
// Before
let timeoutId, ricId, rafId;
timeoutId = setTimeout(() => {
ricId = requestIdleCallback(() => {
rafId = requestAnimationFrame(() => {
// Do something
});
});
}, 3000);
const cancelQueue = () => {
clearTimeout(timeoutId);
cancelIdleCallback(ricId);
cancelAnimationFrame(rafId);
};
// After
const cancelQueue = waitForTimers([3000, 'ric', 'raf'], () => {
// Do something
});
Great for cancellable animations, e.g.
// Toast component (starts off hidden)
const [styles, setStyles] = useState({
transform: 'translateY(1rem)',
opacity: '0',
});
useLayoutEffect(() => {
// Fade-in new toast
let cancel = waitForTimers(['raf'], () => {
setStyles({});
// Fade-out toast after 3 seconds
cancel = waitForTimers([3000, 'raf'], () => {
setStyles({ opacity: '0' });
// Remove toast from DOM after fade-out animation completes
cancel = waitForTimers([200], () => removeToast());
});
});
// Allow cancellation at any point
return () => cancel();
}, []);
return <Toast style={styles}>...</Toast>;