javascript

examples

examples.js
/**
 * ========================================
 * 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()');
Examples - JavaScript Tutorial | DeepML