javascript
examples
examples.js⚡javascript
/**
* ========================================
* 11.5 Timers and Scheduling - Examples
* ========================================
*
* Comprehensive examples of JavaScript timing functions.
*/
/**
* EXAMPLE 1: setTimeout Basics
*
* Execute code after a delay.
*/
// Basic setTimeout
function basicSetTimeout() {
console.log('Starting...');
setTimeout(() => {
console.log('This runs after 2 seconds');
}, 2000);
console.log('This runs immediately');
}
// With arguments
function setTimeoutWithArgs() {
function greet(name, greeting) {
console.log(`${greeting}, ${name}!`);
}
// Pass arguments after delay
setTimeout(greet, 1000, 'John', 'Hello');
}
// Cancelling a timeout
function cancelTimeout() {
const timeoutId = setTimeout(() => {
console.log('This will never run');
}, 5000);
// Cancel before it executes
setTimeout(() => {
clearTimeout(timeoutId);
console.log('Timeout cancelled');
}, 1000);
}
/**
* EXAMPLE 2: setInterval Basics
*
* Execute code repeatedly at intervals.
*/
function basicInterval() {
let count = 0;
const intervalId = setInterval(() => {
count++;
console.log(`Count: ${count}`);
if (count >= 5) {
clearInterval(intervalId);
console.log('Interval stopped');
}
}, 1000);
return intervalId;
}
// Self-correcting interval (accounts for drift)
function accurateInterval(callback, interval) {
let expected = Date.now() + interval;
function step() {
const drift = Date.now() - expected;
callback();
expected += interval;
setTimeout(step, Math.max(0, interval - drift));
}
setTimeout(step, interval);
}
// Example of interval drift
function demonstrateDrift() {
let count = 0;
const start = Date.now();
const id = setInterval(() => {
count++;
const elapsed = Date.now() - start;
const expected = count * 100;
console.log(
`Count: ${count}, Elapsed: ${elapsed}ms, Expected: ${expected}ms, Drift: ${
elapsed - expected
}ms`
);
if (count >= 20) clearInterval(id);
}, 100);
}
/**
* EXAMPLE 3: Zero Delay setTimeout
*
* Understanding the event loop.
*/
function eventLoopDemo() {
console.log('1 - Synchronous');
setTimeout(() => console.log('2 - setTimeout 0'), 0);
Promise.resolve().then(() => console.log('3 - Promise (microtask)'));
console.log('4 - Synchronous');
// Output order: 1, 4, 3, 2
// Microtasks (Promises) run before macrotasks (setTimeout)
}
// Breaking up long-running tasks
function processLargeArray(array, processFn, chunkSize = 100) {
let index = 0;
function processChunk() {
const end = Math.min(index + chunkSize, array.length);
for (; index < end; index++) {
processFn(array[index], index);
}
if (index < array.length) {
setTimeout(processChunk, 0);
} else {
console.log('Processing complete');
}
}
processChunk();
}
/**
* EXAMPLE 4: requestAnimationFrame
*
* Smooth animations synced with display refresh.
*/
// Basic animation loop
function animateElement(element) {
let position = 0;
let frameId;
function animate(timestamp) {
position += 2;
element.style.transform = `translateX(${position}px)`;
if (position < 500) {
frameId = requestAnimationFrame(animate);
}
}
frameId = requestAnimationFrame(animate);
// Return cancel function
return () => cancelAnimationFrame(frameId);
}
// Time-based animation (frame-rate independent)
function animateWithDelta(element, duration = 2000) {
let startTime;
let frameId;
function animate(timestamp) {
if (!startTime) startTime = timestamp;
const elapsed = timestamp - startTime;
const progress = Math.min(elapsed / duration, 1);
// Easing function (ease-out)
const eased = 1 - Math.pow(1 - progress, 3);
element.style.transform = `translateX(${eased * 300}px)`;
if (progress < 1) {
frameId = requestAnimationFrame(animate);
}
}
frameId = requestAnimationFrame(animate);
return () => cancelAnimationFrame(frameId);
}
// FPS counter
function createFPSCounter() {
let frames = 0;
let lastTime = performance.now();
let fps = 0;
function countFrame(timestamp) {
frames++;
if (timestamp - lastTime >= 1000) {
fps = frames;
frames = 0;
lastTime = timestamp;
console.log(`FPS: ${fps}`);
}
requestAnimationFrame(countFrame);
}
requestAnimationFrame(countFrame);
}
/**
* EXAMPLE 5: requestIdleCallback
*
* Run code when browser is idle.
*/
// Basic idle callback
function scheduleIdleWork(tasks) {
function processTasks(deadline) {
// Process while we have time remaining
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
const task = tasks.shift();
task();
}
// Schedule more work if needed
if (tasks.length > 0) {
requestIdleCallback(processTasks);
}
}
requestIdleCallback(processTasks);
}
// With timeout fallback
function scheduleWithTimeout(callback, timeout = 2000) {
if ('requestIdleCallback' in window) {
requestIdleCallback(callback, { timeout });
} else {
// Fallback for Safari
setTimeout(
() =>
callback({
didTimeout: false,
timeRemaining: () => 50,
}),
1
);
}
}
// Idle-based data loading
function idleDataLoader(items, loadFn) {
const queue = [...items];
const loaded = [];
return new Promise((resolve) => {
function processQueue(deadline) {
while (deadline.timeRemaining() > 1 && queue.length > 0) {
const item = queue.shift();
loaded.push(loadFn(item));
}
if (queue.length > 0) {
requestIdleCallback(processQueue);
} else {
resolve(loaded);
}
}
requestIdleCallback(processQueue);
});
}
/**
* EXAMPLE 6: Debounce Implementation
*
* Wait for pause before executing.
*/
// Basic debounce
function debounce(fn, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
}
// Debounce with immediate option
function debounceAdvanced(fn, delay, options = {}) {
let timeoutId;
let lastArgs;
const { leading = false, trailing = true } = options;
return function (...args) {
lastArgs = args;
const shouldCallNow = leading && !timeoutId;
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
timeoutId = null;
if (trailing && lastArgs) {
fn.apply(this, lastArgs);
lastArgs = null;
}
}, delay);
if (shouldCallNow) {
fn.apply(this, args);
}
};
}
// Debounce with cancel and flush
function debounceWithControls(fn, delay) {
let timeoutId;
let lastArgs;
let lastThis;
function debounced(...args) {
lastArgs = args;
lastThis = this;
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.apply(lastThis, lastArgs);
lastArgs = lastThis = null;
}, delay);
}
debounced.cancel = () => {
clearTimeout(timeoutId);
lastArgs = lastThis = null;
};
debounced.flush = () => {
if (timeoutId) {
clearTimeout(timeoutId);
fn.apply(lastThis, lastArgs);
lastArgs = lastThis = null;
}
};
return debounced;
}
/**
* EXAMPLE 7: Throttle Implementation
*
* Limit execution rate.
*/
// Basic throttle
function throttle(fn, limit) {
let waiting = false;
return function (...args) {
if (!waiting) {
fn.apply(this, args);
waiting = true;
setTimeout(() => (waiting = false), limit);
}
};
}
// Throttle with trailing call
function throttleWithTrailing(fn, limit) {
let waiting = false;
let pendingArgs = null;
return function (...args) {
if (!waiting) {
fn.apply(this, args);
waiting = true;
setTimeout(() => {
waiting = false;
if (pendingArgs) {
fn.apply(this, pendingArgs);
pendingArgs = null;
}
}, limit);
} else {
pendingArgs = args;
}
};
}
// RAF-based throttle (for animations)
function throttleRAF(fn) {
let pending = false;
return function (...args) {
if (!pending) {
pending = true;
requestAnimationFrame(() => {
fn.apply(this, args);
pending = false;
});
}
};
}
/**
* EXAMPLE 8: Promise-based Delay
*
* Async-friendly timing functions.
*/
// Simple delay
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// Delay with value
function delayWithValue(ms, value) {
return new Promise((resolve) => setTimeout(() => resolve(value), ms));
}
// Cancellable delay
function cancellableDelay(ms) {
let timeoutId;
let rejectFn;
const promise = new Promise((resolve, reject) => {
rejectFn = reject;
timeoutId = setTimeout(resolve, ms);
});
return {
promise,
cancel: () => {
clearTimeout(timeoutId);
rejectFn(new Error('Cancelled'));
},
};
}
// Usage
async function delayedOperations() {
console.log('Starting');
await delay(1000);
console.log('After 1 second');
const result = await delayWithValue(500, 'Hello');
console.log('Result:', result);
}
/**
* EXAMPLE 9: Polling Pattern
*
* Repeatedly check for a condition.
*/
async function poll(checkFn, interval = 1000, options = {}) {
const { maxAttempts = Infinity, timeout = Infinity } = options;
const startTime = Date.now();
let attempts = 0;
while (attempts < maxAttempts && Date.now() - startTime < timeout) {
const result = await checkFn();
if (result) return result;
attempts++;
await delay(interval);
}
throw new Error('Polling timeout');
}
// Exponential backoff polling
async function pollWithBackoff(checkFn, options = {}) {
const {
initialInterval = 1000,
maxInterval = 30000,
backoffFactor = 2,
maxAttempts = 10,
} = options;
let interval = initialInterval;
let attempts = 0;
while (attempts < maxAttempts) {
const result = await checkFn();
if (result) return result;
attempts++;
await delay(interval);
interval = Math.min(interval * backoffFactor, maxInterval);
}
throw new Error('Max attempts reached');
}
/**
* EXAMPLE 10: Rate Limiter
*
* Control execution rate.
*/
class RateLimiter {
constructor(maxPerSecond) {
this.maxPerSecond = maxPerSecond;
this.tokens = maxPerSecond;
this.lastRefill = Date.now();
this.queue = [];
}
refill() {
const now = Date.now();
const elapsed = now - this.lastRefill;
const newTokens = (elapsed / 1000) * this.maxPerSecond;
this.tokens = Math.min(this.maxPerSecond, this.tokens + newTokens);
this.lastRefill = now;
}
async acquire() {
return new Promise((resolve) => {
const tryAcquire = () => {
this.refill();
if (this.tokens >= 1) {
this.tokens--;
resolve();
} else {
const waitTime = ((1 - this.tokens) / this.maxPerSecond) * 1000;
setTimeout(tryAcquire, waitTime);
}
};
tryAcquire();
});
}
async execute(fn) {
await this.acquire();
return fn();
}
}
// Usage
// const limiter = new RateLimiter(5); // 5 per second
// for (let i = 0; i < 20; i++) {
// limiter.execute(() => console.log('Request', i));
// }
/**
* EXAMPLE 11: Timer Utilities
*
* Helpful timing functions.
*/
// Measure execution time
async function measureTime(fn) {
const start = performance.now();
const result = await fn();
const end = performance.now();
return { result, time: end - start };
}
// Timeout wrapper
function withTimeout(promise, ms, message = 'Timeout') {
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error(message)), ms);
});
return Promise.race([promise, timeout]);
}
// Retry with delay
async function retry(fn, options = {}) {
const { retries = 3, delay: delayMs = 1000, backoff = false } = options;
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (error) {
if (i === retries - 1) throw error;
const wait = backoff ? delayMs * Math.pow(2, i) : delayMs;
await delay(wait);
}
}
}
// Deadline
function createDeadline(ms) {
const deadline = Date.now() + ms;
return {
remaining: () => Math.max(0, deadline - Date.now()),
expired: () => Date.now() >= deadline,
waitUntilExpired: () => delay(Math.max(0, deadline - Date.now())),
};
}
/**
* EXAMPLE 12: Animation Controller
*
* Manage complex animations.
*/
class AnimationController {
constructor() {
this.animations = new Map();
this.running = false;
this.frameId = null;
}
add(id, animateFn) {
this.animations.set(id, {
fn: animateFn,
startTime: null,
});
}
remove(id) {
this.animations.delete(id);
if (this.animations.size === 0) {
this.stop();
}
}
start() {
if (this.running) return;
this.running = true;
const tick = (timestamp) => {
for (const [id, animation] of this.animations) {
if (!animation.startTime) {
animation.startTime = timestamp;
}
const elapsed = timestamp - animation.startTime;
const shouldContinue = animation.fn(elapsed, timestamp);
if (!shouldContinue) {
this.animations.delete(id);
}
}
if (this.running && this.animations.size > 0) {
this.frameId = requestAnimationFrame(tick);
}
};
this.frameId = requestAnimationFrame(tick);
}
stop() {
this.running = false;
if (this.frameId) {
cancelAnimationFrame(this.frameId);
this.frameId = null;
}
}
pause() {
this.running = false;
if (this.frameId) {
cancelAnimationFrame(this.frameId);
}
}
}
/**
* EXAMPLE 13: Schedule Manager
*
* Manage multiple scheduled tasks.
*/
class ScheduleManager {
constructor() {
this.tasks = new Map();
}
setTimeout(id, callback, delay) {
this.clear(id);
const timeoutId = setTimeout(() => {
this.tasks.delete(id);
callback();
}, delay);
this.tasks.set(id, { type: 'timeout', id: timeoutId });
}
setInterval(id, callback, interval) {
this.clear(id);
const intervalId = setInterval(callback, interval);
this.tasks.set(id, { type: 'interval', id: intervalId });
}
clear(id) {
const task = this.tasks.get(id);
if (task) {
if (task.type === 'timeout') {
clearTimeout(task.id);
} else {
clearInterval(task.id);
}
this.tasks.delete(id);
}
}
clearAll() {
for (const [id] of this.tasks) {
this.clear(id);
}
}
has(id) {
return this.tasks.has(id);
}
}
// Usage
const scheduler = new ScheduleManager();
// scheduler.setTimeout('autoSave', () => save(), 30000);
// scheduler.setInterval('heartbeat', () => ping(), 5000);
// scheduler.clear('autoSave');
console.log('Timer and Scheduling examples loaded!');
console.log('Try: basicSetTimeout(), basicInterval(), eventLoopDemo()');