Students will be able to use JavaScript timing events (setTimeout and setInterval) to create dynamic, accessible, and secure web pages, and to integrate these techniques with the broader web‑development concepts required by the syllabus (HTML5, CSS, DOM, accessibility, security, performance, and cross‑topic applications such as mail‑merge, graphics/animation and web‑programming).
<!DOCTYPE html>, <html>, <head>, <body>.<header>, <nav>, <main>, <section>, <footer>.<link rel="stylesheet" href="style.css"> and <script src="script.js"></script>.display, position, background, media queries for progressive enhancement.let, const, var (scope reminder).if / else, for, while.The browser executes JavaScript on a single thread. After each piece of code runs, the engine checks the task queue. Timer callbacks are placed on this queue once their delay has elapsed. When the call stack is empty, the event loop moves the next task from the queue to the stack and executes it. Because the queue also holds micro‑tasks (e.g., promise callbacks), a timer callback may be delayed further if micro‑tasks are pending.
aria-live regions and provide pause controls so users with disabilities can control automatic updates.setTimeout, and requestAnimationFrame helps students write efficient code.setTimeout() – One‑Off Delayed Executionlet id = setTimeout(callback, delay, …args);
callback when it runs.clearTimeout.function showMessage() {
alert('Hello after 2 seconds!');
}
setTimeout(showMessage, 2000);
let timerId = setTimeout(() => console.log('Will not run'), 5000);
clearTimeout(timerId); // cancels the pending callback
In an exam, you may be asked to identify a security flaw such as:
setTimeout(() => {
document.body.innerHTML = userInput; // ❌ unsafe – XSS risk
}, 1000);
Correct approach: sanitise userInput or use textContent instead of innerHTML.
setInterval() – Repeated Executionlet id = setInterval(callback, interval, …args);
setTimeout but automatically repeats every interval milliseconds.clearInterval(id).function updateClock() {
const now = new Date();
document.getElementById('clock').textContent = now.toLocaleTimeString();
}
let clockId = setInterval(updateClock, 1000); // update every second
clearInterval(clockId); // stops the periodic updates
setInterval does not account for the time taken by the callback. Over many iterations the schedule can slip (drift). For more accurate timing use a recursive setTimeout pattern (see Section 13).
requestAnimationFrame() – Animation‑Friendly Alternativelet start = null;
const box = document.getElementById('box');
function step(timestamp) {
if (!start) start = timestamp;
const progress = timestamp - start;
box.style.transform = `translateX(${progress / 5}px)`;
if (progress < 2000) { // stop after 2 seconds
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
| Feature | setTimeout |
setInterval |
requestAnimationFrame |
|---|---|---|---|
| Execution pattern | Single call after the delay | Repeated calls at the interval | Repeated calls synced to the display refresh |
| Typical use‑case | Delays, one‑off actions, debouncing | Clocks, polls, simple non‑visual loops | Visual animations, canvas updates, CSS transitions |
| Stopping mechanism | clearTimeout(id) |
clearInterval(id) |
Cancel by not calling requestAnimationFrame again |
| Potential drift | None (single execution) | Can accumulate; mitigate with recursive setTimeout |
None – runs just before each repaint |
| Minimum delay | ~4 ms for nested timers | ~4 ms for nested timers | Controlled by the monitor’s refresh rate (≈16 ms for 60 Hz) |
| Return value | Numeric timer identifier | Numeric timer identifier | Numeric request ID (can be cancelled with cancelAnimationFrame) |
<div id="clock" aria-live="polite">--:--:--</div>
<button id="pauseClock">Pause</button>
<script>
let clockId = null;
function updateClock() {
const now = new Date();
document.getElementById('clock').textContent = now.toLocaleTimeString();
}
function startClock() {
if (!clockId) clockId = setInterval(updateClock, 1000);
}
function pauseClock() {
clearInterval(clockId);
clockId = null;
}
document.getElementById('pauseClock').addEventListener('click', pauseClock);
startClock(); // start automatically
</script>
function randomColour() {
const r = Math.floor(Math.random()*256);
const g = Math.floor(Math.random()*256);
const b = Math.floor(Math.random()*256);
return `rgb(${r},${g},${b})`;
}
let colourId = null;
function startColourChange() {
colourId = setInterval(() => {
document.body.style.backgroundColor = randomColour();
}, 3000);
// stop automatically after 30 seconds
setTimeout(() => clearInterval(colourId), 30000);
}
function pauseColourChange() {
clearInterval(colourId);
colourId = null;
}
document.addEventListener('DOMContentLoaded', startColourChange);
Timers are often combined with user‑generated events such as clicks or form input.
<button id="start">Start</button>
<button id="stop">Stop</button>
<img id="slide" src="img1.jpg" alt="slideshow image">
<script>
const images = ['img1.jpg','img2.jpg','img3.jpg'];
let index = 0;
let slideId = null;
function showNext() {
index = (index + 1) % images.length;
document.getElementById('slide').src = images[index];
}
document.getElementById('start').addEventListener('click', () => {
if (!slideId) slideId = setInterval(showNext, 2000);
});
document.getElementById('stop').addEventListener('click', () => {
clearInterval(slideId);
slideId = null;
});
</script>
addEventListener keeps JavaScript separate from HTML – a key principle of progressive enhancement.setTimeout and setInterval are classic callback‑based APIs.function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function demo() {
console.log('Start');
await delay(2000);
console.log('Two seconds later');
}
demo();
function poll(url, interval) {
const id = setInterval(async () => {
const resp = await fetch(url);
const data = await resp.json();
console.log(data);
}, interval);
return id; // caller can clearInterval when done
}
const pollId = poll('data.json', 5000);
// later: clearInterval(pollId);
innerHTML inside a timer callback – this creates an XSS risk.Identify the vulnerability in the snippet below and suggest a safe alternative:
setTimeout(() => {
document.body.innerHTML = userSuppliedHTML; // ❌ unsafe
}, 0);
Safe version:
setTimeout(() => {
const div = document.createElement('div');
div.textContent = userSuppliedHTML; // treats content as plain text
document.body.appendChild(div);
}, 0);
setInterval does not account for the time taken by the callback; over many cycles the schedule can slip.setTimeout pattern for more accurate timing:
function tick() {
// …do work…
setTimeout(tick, 1000); // schedule next tick after work finishes
}
tick();
requestAnimationFrame (Section 7) because it is synchronised with the display refresh rate.Timelines are not isolated; they can be combined with other A‑Level topics:
setTimeout to display a preview of a merged document a few seconds after the user clicks “Generate”.requestAnimationFrame or a fast setInterval loop; timers also enable sprite animation frames.setInterval combined with the Fetch API.window.unload).this – Arrow functions preserve lexical this; regular functions may need .bind(this) when used as callbacks.console.log with timestamps to verify drift:
console.log('Tick', new Date().toISOString());
window.addEventListener('unload', …) handler that clears all active timers.for (var i = 1; i <= 5; i++) {
setTimeout(function() {
console.log(i);
}, i * 1000);
}
setTimeout, create a debounce function that limits how often a handler runs while a user types in a text field. Demonstrate it with a live‑search field that logs the query after the user stops typing for 300 ms.poll(url, interval) that fetches JSON data from url every interval milliseconds and logs the result. Show how to stop the polling after 20 seconds.Create an account or Login to take a Quiz
Log in to suggest improvements to this note.
Your generous donation helps us continue providing free Cambridge IGCSE & A-Level resources, past papers, syllabus notes, revision questions, and high-quality online tutoring to students across Kenya.