Skip to main content
Background Image
  1. Posts/

JavaScript Timers - Interval and Timeout

·872 words·5 mins
Cayden
Author
Cayden
Independent developer sharing daily experiences, challenges and growth in the journey of building products
Table of Contents

Today I wrote a sidebar sharing widget using native JavaScript, and the main knowledge used was timers, so I’ll take this opportunity to summarize the related content about timers.

First, timers are divided into interval call timers and timeout call timers. They are very similar, with basically the same commands.

Interval Timer Code
#

// Declare an interval timer and assign the ID to intervalId
var intervalId = setInterval(function() {
    // Execute code
}, 1000);

// Clear the timer
clearInterval(intervalId);

Timeout Timer Code
#

// Declare a timeout timer and assign the ID to timeoutId
var timeoutId = setTimeout(function() {
    // Execute code
}, 1000);

// Clear the timer
clearTimeout(timeoutId);

Key Differences
#

1. Execution Frequency
#

  • setInterval: Executes repeatedly at specified intervals
  • setTimeout: Executes only once after the specified delay

2. Use Cases
#

  • setInterval: For recurring tasks (animations, polling, updates)
  • setTimeout: For delayed execution (debouncing, one-time actions)

Practical Examples
#

1. Digital Clock with setInterval
#

function updateClock() {
    const now = new Date();
    const timeString = now.toLocaleTimeString();
    document.getElementById('clock').textContent = timeString;
}

// Update clock every second
const clockInterval = setInterval(updateClock, 1000);

// Stop the clock after 10 seconds
setTimeout(() => {
    clearInterval(clockInterval);
}, 10000);

2. Debouncing with setTimeout
#

function debounce(func, delay) {
    let timeoutId;
    return function(...args) {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => func.apply(this, args), delay);
    };
}

// Usage
const debouncedSearch = debounce(function(query) {
    console.log('Searching for:', query);
}, 300);

// This will only execute after user stops typing for 300ms
document.getElementById('search').addEventListener('input', function(e) {
    debouncedSearch(e.target.value);
});

3. Animation with setInterval
#

function animateElement(element, start, end, duration) {
    const startTime = Date.now();
    const interval = setInterval(() => {
        const elapsed = Date.now() - startTime;
        const progress = Math.min(elapsed / duration, 1);
        
        const current = start + (end - start) * progress;
        element.style.left = current + 'px';
        
        if (progress === 1) {
            clearInterval(interval);
        }
    }, 16); // ~60fps
}

// Usage
const element = document.getElementById('moving-element');
animateElement(element, 0, 500, 1000); // Move 500px over 1 second

4. Polling with setInterval
#

function pollServer() {
    fetch('/api/status')
        .then(response => response.json())
        .then(data => {
            if (data.status === 'complete') {
                clearInterval(pollInterval);
                console.log('Task completed!');
            }
        })
        .catch(error => {
            console.error('Polling error:', error);
            clearInterval(pollInterval);
        });
}

// Start polling every 2 seconds
const pollInterval = setInterval(pollServer, 2000);

Best Practices
#

1. Always Clear Timers
#

// Good: Clear timer when component unmounts
class MyComponent {
    constructor() {
        this.timer = setInterval(this.updateData, 1000);
    }
    
    destroy() {
        clearInterval(this.timer);
    }
}

2. Use Modern Alternatives When Possible
#

// Instead of setInterval for animations
function animateWithRAF() {
    function animate() {
        // Animation code
        requestAnimationFrame(animate);
    }
    animate();
}

// Instead of setTimeout for promises
function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// Usage
async function example() {
    console.log('Start');
    await delay(1000);
    console.log('After 1 second');
}

3. Handle Edge Cases
#

function safeSetInterval(callback, delay) {
    let intervalId;
    let isActive = true;
    
    intervalId = setInterval(() => {
        if (!isActive) {
            clearInterval(intervalId);
            return;
        }
        
        try {
            callback();
        } catch (error) {
            console.error('Timer callback error:', error);
            clearInterval(intervalId);
        }
    }, delay);
    
    return {
        clear: () => {
            isActive = false;
            clearInterval(intervalId);
        }
    };
}

4. Performance Considerations
#

// Bad: Too frequent updates
setInterval(updateUI, 1); // 1000fps - unnecessary

// Good: Reasonable frequency
setInterval(updateUI, 16); // ~60fps - smooth animation

// Better: Use requestAnimationFrame for animations
function smoothAnimation() {
    function animate() {
        updateUI();
        requestAnimationFrame(animate);
    }
    animate();
}

Common Pitfalls
#

1. Memory Leaks
#

// Bad: Timer not cleared
function startTimer() {
    setInterval(() => {
        // This will run forever
    }, 1000);
}

// Good: Store reference and clear when needed
function startTimer() {
    const timer = setInterval(() => {
        // Timer logic
    }, 1000);
    
    // Clear when appropriate
    setTimeout(() => clearInterval(timer), 10000);
}

2. Accumulating Timers
#

// Bad: Multiple timers without clearing
function startMultipleTimers() {
    setInterval(updateData, 1000);
    setInterval(updateData, 1000); // Creates another timer
}

// Good: Clear existing timer first
let dataTimer;
function startDataTimer() {
    if (dataTimer) {
        clearInterval(dataTimer);
    }
    dataTimer = setInterval(updateData, 1000);
}

3. Blocking Operations
#

// Bad: Blocking operation in timer
setInterval(() => {
    // This blocks the thread
    for (let i = 0; i < 1000000; i++) {
        // Heavy computation
    }
}, 100);

// Good: Use Web Workers for heavy operations
const worker = new Worker('heavy-computation.js');
setInterval(() => {
    worker.postMessage({ data: 'process this' });
}, 100);

Modern Alternatives
#

1. requestAnimationFrame for Animations
#

function animate() {
    // Animation code
    requestAnimationFrame(animate);
}
animate();

2. Promise-based Delays
#

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

// Usage
async function example() {
    await delay(1000);
    console.log('1 second later');
}

3. AbortController for Cancellation
#

function createCancellableTimer(callback, delay) {
    const controller = new AbortController();
    
    const timer = setTimeout(() => {
        if (!controller.signal.aborted) {
            callback();
        }
    }, delay);
    
    return {
        cancel: () => {
            controller.abort();
            clearTimeout(timer);
        }
    };
}

Conclusion
#

JavaScript timers (setInterval and setTimeout) are powerful tools for:

  1. Scheduling recurring tasks with setInterval
  2. Delaying execution with setTimeout
  3. Creating animations and effects
  4. Implementing polling and debouncing

Key best practices:

  • Always clear timers when no longer needed
  • Use appropriate timing intervals
  • Handle errors in timer callbacks
  • Consider modern alternatives like requestAnimationFrame
  • Be mindful of performance implications

Remember: timers are essential for creating interactive and dynamic web applications, but they should be used responsibly to avoid memory leaks and performance issues.