javascript

examples

examples.js
/**
 * ========================================
 * 9.5 TIMERS AND INTERVALS - CODE EXAMPLES
 * ========================================
 */

/**
 * EXAMPLE 1: Basic setTimeout
 */
console.log('--- Example 1: Basic setTimeout ---');

setTimeout(() => {
  console.log('Executed after 100ms');
}, 100);

// With named function
function greet(name) {
  console.log(`Hello, ${name}!`);
}

setTimeout(greet, 200, 'Alice'); // Pass argument after delay

/**
 * EXAMPLE 2: Canceling a Timeout
 */
console.log('\n--- Example 2: Cancel Timeout ---');

const timerId = setTimeout(() => {
  console.log("This won't run");
}, 5000);

// Cancel immediately
clearTimeout(timerId);
console.log('Timeout cancelled');

/**
 * EXAMPLE 3: Zero Delay Behavior
 */
console.log('\n--- Example 3: Zero Delay ---');

console.log('1. Sync first');

setTimeout(() => {
  console.log('3. Timeout (even with 0ms)');
}, 0);

console.log('2. Sync second');

// Output: 1, 2, 3 - because timers go through event loop

/**
 * EXAMPLE 4: Basic setInterval
 */
console.log('\n--- Example 4: setInterval ---');

let count = 0;
const intervalId = setInterval(() => {
  count++;
  console.log(`Tick ${count}`);

  if (count >= 3) {
    clearInterval(intervalId);
    console.log('Interval stopped');
  }
}, 100);

/**
 * EXAMPLE 5: Promise-based Delay
 */
console.log('\n--- Example 5: Delay Promise ---');

function delay(ms, value) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(value), ms);
  });
}

delay(150, 'delayed value').then((value) => console.log('Received:', value));

/**
 * EXAMPLE 6: Timeout Promise
 */
console.log('\n--- Example 6: Timeout Promise ---');

function timeout(ms, message = 'Timeout') {
  return new Promise((_, reject) => {
    setTimeout(() => reject(new Error(message)), ms);
  });
}

// Race: fast operation vs timeout
Promise.race([delay(50, 'Fast!'), timeout(200, 'Too slow')]).then((result) =>
  console.log('Winner:', result)
);

/**
 * EXAMPLE 7: Debounce Implementation
 */
console.log('\n--- Example 7: Debounce ---');

function debounce(fn, wait) {
  let timeoutId;

  return function (...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn.apply(this, args), wait);
  };
}

// Simulate rapid events
const debouncedLog = debounce((msg) => console.log('Debounced:', msg), 100);

// Fire rapidly - only last one executes
debouncedLog('first');
debouncedLog('second');
debouncedLog('third'); // Only this one will log

/**
 * EXAMPLE 8: Debounce with Leading Edge
 */
console.log('\n--- Example 8: Leading Debounce ---');

function debounceLeading(fn, wait) {
  let timeoutId;
  let leading = true;

  return function (...args) {
    if (leading) {
      fn.apply(this, args);
      leading = false;
    }

    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      leading = true;
    }, wait);
  };
}

const leadingDebounced = debounceLeading(
  (msg) => console.log('Leading:', msg),
  100
);

leadingDebounced('first'); // Logs immediately
leadingDebounced('second'); // Ignored
leadingDebounced('third'); // Ignored

/**
 * EXAMPLE 9: Throttle Implementation
 */
console.log('\n--- Example 9: Throttle ---');

function throttle(fn, limit) {
  let inThrottle = false;

  return function (...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => (inThrottle = false), limit);
    }
  };
}

const throttledLog = throttle((msg) => console.log('Throttled:', msg), 100);

// Fire rapidly - some will execute
throttledLog('1'); // Logs
throttledLog('2'); // Ignored
throttledLog('3'); // Ignored
setTimeout(() => throttledLog('4'), 150); // Logs

/**
 * EXAMPLE 10: Throttle with Trailing Edge
 */
console.log('\n--- Example 10: Throttle Trailing ---');

function throttleTrailing(fn, limit) {
  let lastArgs = null;
  let timeoutId = null;

  return function (...args) {
    if (timeoutId === null) {
      fn.apply(this, args);
      timeoutId = setTimeout(() => {
        if (lastArgs) {
          fn.apply(this, lastArgs);
          lastArgs = null;
        }
        timeoutId = null;
      }, limit);
    } else {
      lastArgs = args;
    }
  };
}

const trailingThrottle = throttleTrailing(
  (msg) => console.log('Trailing:', msg),
  100
);

trailingThrottle('first'); // Logs immediately
trailingThrottle('second'); // Saved
trailingThrottle('third'); // Replaces second, logs after 100ms

/**
 * EXAMPLE 11: Self-Correcting Interval
 */
console.log('\n--- Example 11: Self-Correcting Timer ---');

function accurateInterval(callback, interval, iterations = 5) {
  let expected = Date.now() + interval;
  let count = 0;

  function step() {
    const drift = Date.now() - expected;
    count++;
    callback(count, drift);

    if (count >= iterations) return;

    expected += interval;
    setTimeout(step, Math.max(0, interval - drift));
  }

  setTimeout(step, interval);
}

accurateInterval(
  (tick, drift) => {
    console.log(`Accurate tick ${tick}, drift: ${drift}ms`);
  },
  100,
  3
);

/**
 * EXAMPLE 12: Polling with Timeout
 */
console.log('\n--- Example 12: Polling Pattern ---');

class Poller {
  constructor(asyncFn, options = {}) {
    this.asyncFn = asyncFn;
    this.interval = options.interval || 1000;
    this.maxAttempts = options.maxAttempts || Infinity;
    this.running = false;
    this.attempts = 0;
  }

  start() {
    this.running = true;
    this.attempts = 0;
    this.poll();
  }

  stop() {
    this.running = false;
    console.log(`Polling stopped after ${this.attempts} attempts`);
  }

  async poll() {
    if (!this.running) return;

    this.attempts++;

    try {
      const result = await this.asyncFn();
      console.log(`Poll ${this.attempts}:`, result);
    } catch (error) {
      console.log(`Poll ${this.attempts} error:`, error.message);
    }

    if (this.attempts >= this.maxAttempts) {
      this.stop();
      return;
    }

    setTimeout(() => this.poll(), this.interval);
  }
}

// Simulate status check
let status = 0;
const poller = new Poller(
  async () => {
    status++;
    return { ready: status >= 3, progress: status * 33 };
  },
  { interval: 100, maxAttempts: 4 }
);
poller.start();

/**
 * EXAMPLE 13: Event Loop Demonstration
 */
console.log('\n--- Example 13: Event Loop Order ---');

setTimeout(() => {
  console.log('Loop demo - Timeout 1 (macrotask)');
  Promise.resolve().then(() =>
    console.log('Loop demo - Promise inside timeout (microtask)')
  );
}, 300);

Promise.resolve().then(() => {
  console.log('Loop demo - Promise 1 (microtask)');
});

setTimeout(() => {
  console.log('Loop demo - Timeout 2 (macrotask)');
}, 300);

Promise.resolve().then(() => {
  console.log('Loop demo - Promise 2 (microtask)');
});

console.log('Loop demo - Sync code');

/**
 * EXAMPLE 14: Cancellable Delay with AbortController
 */
console.log('\n--- Example 14: AbortController ---');

function cancellableDelay(ms, signal) {
  return new Promise((resolve, reject) => {
    const timeoutId = setTimeout(() => resolve('completed'), ms);

    if (signal) {
      signal.addEventListener('abort', () => {
        clearTimeout(timeoutId);
        reject(new DOMException('Aborted', 'AbortError'));
      });
    }
  });
}

const controller = new AbortController();

cancellableDelay(500, controller.signal)
  .then((result) => console.log('Delay result:', result))
  .catch((error) => console.log('Delay aborted:', error.name));

// Abort after 100ms
setTimeout(() => controller.abort(), 100);

/**
 * EXAMPLE 15: Timer Manager Class
 */
console.log('\n--- Example 15: Timer Manager ---');

class TimerManager {
  constructor() {
    this.timers = new Map();
    this.nextId = 0;
  }

  setTimeout(callback, delay, name = null) {
    const id = ++this.nextId;
    const timerId = setTimeout(() => {
      this.timers.delete(id);
      callback();
    }, delay);

    this.timers.set(id, { type: 'timeout', timerId, name });
    return id;
  }

  setInterval(callback, interval, name = null) {
    const id = ++this.nextId;
    const timerId = setInterval(callback, interval);

    this.timers.set(id, { type: 'interval', timerId, name });
    return id;
  }

  clear(id) {
    const timer = this.timers.get(id);
    if (timer) {
      if (timer.type === 'timeout') {
        clearTimeout(timer.timerId);
      } else {
        clearInterval(timer.timerId);
      }
      this.timers.delete(id);
      return true;
    }
    return false;
  }

  clearAll() {
    const count = this.timers.size;
    this.timers.forEach((timer) => {
      if (timer.type === 'timeout') {
        clearTimeout(timer.timerId);
      } else {
        clearInterval(timer.timerId);
      }
    });
    this.timers.clear();
    return count;
  }

  getActive() {
    return Array.from(this.timers.entries()).map(([id, timer]) => ({
      id,
      type: timer.type,
      name: timer.name,
    }));
  }
}

const manager = new TimerManager();
manager.setTimeout(() => console.log('Managed timeout 1'), 450);
manager.setTimeout(() => console.log('Managed timeout 2'), 500);
const intervalId = manager.setInterval(
  () => console.log('Managed interval'),
  100,
  'myInterval'
);

console.log('Active timers:', manager.getActive());

// Clear interval after 250ms
setTimeout(() => {
  manager.clear(intervalId);
  console.log('After clear:', manager.getActive());
}, 250);

/**
 * EXAMPLE 16: Retry with Exponential Backoff
 */
console.log('\n--- Example 16: Exponential Backoff ---');

async function retryWithBackoff(fn, options = {}) {
  const { maxRetries = 5, baseDelay = 100, maxDelay = 5000 } = options;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (attempt === maxRetries) throw error;

      const exponentialDelay = Math.min(
        baseDelay * Math.pow(2, attempt - 1),
        maxDelay
      );

      // Add jitter (randomness)
      const jitter = exponentialDelay * 0.2 * Math.random();
      const finalDelay = exponentialDelay + jitter;

      console.log(`Retry ${attempt} in ${Math.round(finalDelay)}ms`);
      await delay(finalDelay);
    }
  }
}

let backoffAttempt = 0;
retryWithBackoff(
  async () => {
    backoffAttempt++;
    if (backoffAttempt < 3) throw new Error('Fail');
    return 'Success after retries';
  },
  { maxRetries: 5, baseDelay: 50 }
).then((result) => console.log('Backoff result:', result));

/**
 * EXAMPLE 17: Rate Limiter
 */
console.log('\n--- Example 17: Rate Limiter ---');

class RateLimiter {
  constructor(maxCalls, perMs) {
    this.maxCalls = maxCalls;
    this.perMs = perMs;
    this.calls = [];
  }

  async acquire() {
    const now = Date.now();

    // Remove old calls
    this.calls = this.calls.filter((time) => now - time < this.perMs);

    if (this.calls.length >= this.maxCalls) {
      // Wait until oldest call expires
      const oldestCall = this.calls[0];
      const waitTime = oldestCall + this.perMs - now;
      await delay(waitTime);
      return this.acquire();
    }

    this.calls.push(now);
  }

  async execute(fn) {
    await this.acquire();
    return fn();
  }
}

const limiter = new RateLimiter(2, 200); // 2 calls per 200ms

async function demonstrateRateLimiter() {
  const results = [];
  const tasks = [1, 2, 3, 4, 5].map(async (i) => {
    await limiter.execute(async () => {
      console.log(`Rate limited call ${i} at ${Date.now() % 10000}ms`);
      results.push(i);
    });
  });

  await Promise.all(tasks);
  console.log('Rate limiter complete:', results);
}

demonstrateRateLimiter();

/**
 * EXAMPLE 18: Animation Frame Simulation
 */
console.log('\n--- Example 18: Animation Frame Pattern ---');

// Simulating requestAnimationFrame behavior
class AnimationLoop {
  constructor() {
    this.running = false;
    this.lastTime = 0;
    this.frameCount = 0;
  }

  start(callback, maxFrames = 5) {
    this.running = true;
    this.lastTime = Date.now();
    this.frameCount = 0;

    const loop = () => {
      if (!this.running || this.frameCount >= maxFrames) {
        console.log('Animation stopped');
        return;
      }

      const currentTime = Date.now();
      const deltaTime = currentTime - this.lastTime;
      this.lastTime = currentTime;
      this.frameCount++;

      callback(deltaTime, this.frameCount);

      // Simulate ~60fps (16.67ms per frame)
      setTimeout(loop, 16);
    };

    loop();
  }

  stop() {
    this.running = false;
  }
}

const animation = new AnimationLoop();
animation.start((dt, frame) => {
  console.log(`Frame ${frame}: ${dt}ms since last frame`);
});

/**
 * EXAMPLE 19: Countdown Timer
 */
console.log('\n--- Example 19: Countdown Timer ---');

class Countdown {
  constructor(seconds, onTick, onComplete) {
    this.remaining = seconds;
    this.onTick = onTick;
    this.onComplete = onComplete;
    this.intervalId = null;
  }

  start() {
    this.onTick(this.remaining);

    this.intervalId = setInterval(() => {
      this.remaining--;

      if (this.remaining <= 0) {
        this.stop();
        this.onComplete();
      } else {
        this.onTick(this.remaining);
      }
    }, 1000);
  }

  stop() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
  }

  pause() {
    this.stop();
  }

  resume() {
    if (this.remaining > 0 && !this.intervalId) {
      this.start();
    }
  }
}

// Use with fast timing for demo
const countdown = new Countdown(
  3,
  (remaining) => console.log(`Countdown: ${remaining}s`),
  () => console.log('Countdown complete!')
);

// Start after other demos have initialized
setTimeout(() => {
  console.log('\n--- Starting Countdown Demo ---');
  // Override for faster demo
  countdown.intervalId = setInterval(() => {
    countdown.remaining--;
    if (countdown.remaining <= 0) {
      countdown.stop();
      countdown.onComplete();
    } else {
      countdown.onTick(countdown.remaining);
    }
  }, 200);
  countdown.onTick(3);
}, 800);

/**
 * EXAMPLE 20: Task Scheduler
 */
console.log('\n--- Example 20: Task Scheduler ---');

class TaskScheduler {
  constructor() {
    this.tasks = [];
  }

  scheduleOnce(name, callback, delayMs) {
    const timeoutId = setTimeout(() => {
      this.removeTask(timeoutId);
      callback();
    }, delayMs);

    this.tasks.push({
      id: timeoutId,
      name,
      type: 'once',
      scheduledFor: Date.now() + delayMs,
    });

    return timeoutId;
  }

  scheduleRepeating(name, callback, intervalMs, count = Infinity) {
    let remaining = count;

    const intervalId = setInterval(() => {
      remaining--;
      callback(count - remaining);

      if (remaining <= 0) {
        this.cancel(intervalId);
      }
    }, intervalMs);

    this.tasks.push({
      id: intervalId,
      name,
      type: 'repeating',
      interval: intervalMs,
    });

    return intervalId;
  }

  cancel(taskId) {
    const task = this.tasks.find((t) => t.id === taskId);
    if (task) {
      if (task.type === 'once') {
        clearTimeout(task.id);
      } else {
        clearInterval(task.id);
      }
      this.removeTask(taskId);
      console.log(`Cancelled task: ${task.name}`);
    }
  }

  removeTask(taskId) {
    this.tasks = this.tasks.filter((t) => t.id !== taskId);
  }

  getScheduledTasks() {
    return this.tasks.map((t) => ({
      name: t.name,
      type: t.type,
    }));
  }

  cancelAll() {
    this.tasks.forEach((task) => {
      if (task.type === 'once') {
        clearTimeout(task.id);
      } else {
        clearInterval(task.id);
      }
    });
    const count = this.tasks.length;
    this.tasks = [];
    return count;
  }
}

const scheduler = new TaskScheduler();

scheduler.scheduleOnce('cleanup', () => console.log('Cleanup executed'), 1500);

scheduler.scheduleRepeating(
  'heartbeat',
  (n) => console.log(`Heartbeat ${n}`),
  300,
  3
);

console.log('Scheduled tasks:', scheduler.getScheduledTasks());

console.log('\n========================================');
console.log('Timer Examples Loaded');
console.log('(Results will appear asynchronously)');
console.log('========================================');
Examples - JavaScript Tutorial | DeepML