Frontend Master

JavaScript Curriculum

Timers & Animation Loop
+60 XP

Timers & Animation Loop

medium
~30 min·60 XP

The coffee shop menu needs a countdown timer for flash sales, a toast notification that disappears after 3 seconds, and a smooth animated banner. Each needs a different timer approach.

Timers & Animation Loop

JavaScript is single-threaded — it can only do one thing at a time. Timers schedule callbacks for later without blocking the thread. requestAnimationFrame syncs your animations with the display refresh rate.

setTimeout & setInterval

Run code once after a delay, or repeatedly at an interval:

timers.js
Delay (ms)1000ms
// Use the buttons to fire timers
// setTimeout — run once after delay:
const id = setTimeout(() => doSomething(), 2000)
clearTimeout(id)  // cancel before it fires

// setInterval — run repeatedly:
const id = setInterval(() => tick(), 1000)
clearInterval(id)  // always store the id to stop it
⚠️Always clear your intervals
A leaked `setInterval` runs forever — even after the user navigates away in a SPA. Always store the return value and call `clearInterval(id)` when done. In React, clean up in the `useEffect` return function.

Countdown Timer

A real countdown built with setInterval — with pause, resume, and reset:

countdown.js
10
seconds
let count = 10
const id = setInterval(() => {
  count--
  display.textContent = count
  if (count <= 0) {
    clearInterval(id)
    showSuccess()
  }
}, 1000)
💡Use elapsed time, not tick count
Instead of counting ticks (`tick++`), track `Date.now() - startTime`. Tick counting drifts over time — the interval fires at approximately 1000ms but never exactly. Time-based logic stays accurate even if the tab is throttled.

requestAnimationFrame — Smooth Animation Loop

The browser calls your function before each repaint — typically 60 times per second:

raf-animation.js
requestAnimationFrame
Synced to display refresh (60fps+)
Pauses when tab hidden — saves battery
Smooth, no frame tearing
Browser can optimise
Slightly more complex to write
setInterval(fn, 16)
Simple to write
Not synced to display — frame tearing
Still runs in hidden tabs — wastes battery
Intervals drift over time
Can stack if JS is slow
function animate(timestamp) {
  const elapsed = timestamp - startTime
  // Update position based on elapsed time:
  el.style.transform =
    `translateX(${Math.sin(elapsed/1000) * 100}px)`

  requestAnimationFrame(animate) // loop
}

// Start:
let startTime
requestAnimationFrame(ts => {
  startTime = ts
  requestAnimationFrame(animate)
})

// Stop:
cancelAnimationFrame(rafId)
ℹ️Never animate with setInterval
setInterval at 16ms sounds like 60fps but it is not — it fires regardless of whether the browser is ready to paint, causing dropped frames. `requestAnimationFrame` fires exactly when the browser is about to repaint, giving you smooth, efficient animation that also pauses when the tab is hidden.

Your Challenge

Build showToast(msg, ms) — creates a div, appends to body, removes after ms using setTimeout. Then add a CSS entry animation. Use requestAnimationFrame to animate the width of a progress bar from 0 to 100% over exactly 2 seconds using timestamp math.

Challenge

Build a toast notification system: showToast(message, duration) creates a .toast element, appends it to the body, and uses setTimeout to remove it after 'duration' ms. Then animate its entry with requestAnimationFrame — slide in from the bottom over 300ms.

setTimeoutsetIntervalclearTimeoutclearIntervalrequestAnimationFramecancelAnimationFrametimestampanimation-loop60fps
Timers & Animation Loop | Nexus Learn