Understanding requestAnimationFrame: Usage, Advantages, and Practical Examples
This article explains the requestAnimationFrame API, demonstrates basic and recursive usage with code samples, compares it to setTimeout/setInterval, shows how to cancel frames, and presents real‑world front‑end scenarios such as smooth animations and scroll‑loading optimizations.
requestAnimationFrame is a browser API that synchronizes JavaScript animation callbacks with the display's refresh cycle, providing front‑end developers a way to create smoother, performance‑friendly animations.
Basic usage involves a single call that executes a callback once:
<script lang="ts" setup>
function init() { console.log('Hello, requestAnimationFrame'); }
requestAnimationFrame(init);
</script>For continuous animation, the callback must call requestAnimationFrame recursively, allowing the browser to match the callback frequency to the screen's refresh rate.
<script lang="ts" setup>
function init() { console.log('Recursive call'); requestAnimationFrame(init); }
requestAnimationFrame(init);
</script>The callback receives a single timestamp argument representing the time when the previous frame finished rendering, which can be used to calculate animation progress.
<script setup>
function init(timestamp) { console.log('Timestamp:', timestamp); requestAnimationFrame(init); }
requestAnimationFrame(init);
</script>To stop an animation, use window.cancelAnimationFrame with the identifier returned by requestAnimationFrame :
<template>
<button @click="stop">Stop</button>
</template>
<script setup>
let reqId;
function loop() { reqId = requestAnimationFrame(loop); }
requestAnimationFrame(loop);
function stop() { cancelAnimationFrame(reqId); }
</script>Advantages over setTimeout and setInterval include:
Smoother animation because the browser aligns callbacks with VSync signals.
Automatic adaptation to the display's refresh rate (e.g., 60 Hz → ~16.7 ms per frame).
Reduced CPU usage when the page is in a background tab, as the API pauses execution.
Typical use cases demonstrated are:
Simple rotating image
<template>
<div class="earth" :style="imgStyle"></div>
</template>
<script setup>
import { reactive, onMounted, onUnmounted } from 'vue';
const imgStyle = reactive({ transform: 'rotate(0deg)' });
let rafId;
function animate(time) { imgStyle.transform = `rotate(${(time % 10000) / 5}deg)`; rafId = requestAnimationFrame(animate); }
onMounted(() => rafId = requestAnimationFrame(animate));
onUnmounted(() => cancelAnimationFrame(rafId));
</script>
<style scoped>
.earth { width:100px;height:100px;background-image:url('...');border-radius:50%; }
</style>Scroll‑loading optimization
<template>
<div class="container" ref="scrollRef" @scroll="handleScroll">
<div v-for="item in items" :key="item" class="item">{{ item }}</div>
<div v-if="loading" class="loading">Loading...</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
const items = ref(Array.from({length:50},(_,i)=>`Test ${i+1}`));
const loading = ref(false);
let rafId: number | null = null;
function checkScroll() { /* load more when near bottom */ }
function handleScroll() { if (rafId) cancelAnimationFrame(rafId); rafId = requestAnimationFrame(checkScroll); }
onMounted(() => {/* add listeners if needed */});
onUnmounted(() => { if (rafId) cancelAnimationFrame(rafId); });
</script>In conclusion, requestAnimationFrame can be employed wherever a page needs smooth, frame‑rate‑aware updates, ranging from simple UI effects to complex game loops and dynamic layout calculations.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.