BRUCE_FEBRUCE_FE

EN/CH Mode

BRUCE_FE JS Interview Notes - Implementing Promise Sleep Function

Learn how to implement Promise Sleep function in JavaScript, handle delayed execution, scheduled tasks and animations, and master the fundamental tools of asynchronous programming.

影片縮圖

Lazy to read articles? Then watch videos!

Promise Sleep Function Overview

Promise Sleep function is a simple but practical tool that allows code to pause execution for a specified time. In various asynchronous operations, the sleep function is very useful, especially when you need to delay execution, simulate network delays, or control animation timing.

Why Do We Need Sleep Function?

  • 1. Control Execution Rhythm: Add delays between consecutive operations to avoid overly frequent operations
  • 2. Simulate Network Delay: Test code's ability to handle delays
  • 3. Animation and Visual Effects: Control intervals between consecutive visual changes
  • 4. API Rate Limiting: Avoid sending too many requests in a short time
  • 5. Retry Mechanism: Implement retry strategies like exponential backoff

Basic Promise Sleep Implementation

Below is a simple Promise Sleep function implementation:

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

// Usage example
async function example() {
  console.log('Start');
  
  await sleep(2000); // Pause for 2 seconds
  
  console.log('After 2 seconds'); // Execute after 2 seconds
}

example();

This function creates a new Promise that calls resolve after the specified milliseconds. Combined with async/await syntax, it allows code to pause execution for a specified time.

Advanced Promise Sleep Features

We can extend the basic sleep function to add more features:

Sleep with Return Value

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

// Usage example
async function example() {
  console.log('Start');
  
  const result = await sleepWithValue(2000, 'Delayed returned data');
  
  console.log(result); // Display after 2 seconds: Delayed returned data
}

example();

Cancellable Sleep

function cancellableSleep(ms) {
  let timeoutId;
  
  const promise = new Promise(resolve => {
    timeoutId = setTimeout(resolve, ms);
  });
  
  // Add cancel method
  promise.cancel = function() {
    clearTimeout(timeoutId);
  };
  
  return promise;
}

// Usage example
async function example() {
  console.log('Start');
  
  const sleepPromise = cancellableSleep(5000);
  
  // Cancel sleep after 2 seconds
  setTimeout(() => {
    console.log('Cancel sleep');
    sleepPromise.cancel();
  }, 2000);
  
  try {
    await sleepPromise;
    console.log('After 5 seconds'); // Won't execute because cancelled
  } catch (error) {
    console.log('Sleep was cancelled');
  }
}

example();

Practical Application Scenarios

Here are some practical applications of Promise Sleep function:

1. Implementing API Request Retry Mechanism

async function fetchWithRetry(url, options = {}, maxRetries = 3) {
  const { retryDelay = 1000 } = options;
  
  let lastError;
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      // Try to make request
      const response = await fetch(url, options);
      
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      
      return await response.json();
    } catch (error) {
      console.log(`Attempt ${attempt + 1} failed: ${error.message}`);
      lastError = error;
      
      if (attempt < maxRetries - 1) {
        // Use exponential backoff strategy to calculate next retry delay
        const delay = retryDelay * Math.pow(2, attempt);
        console.log(`Waiting ${delay}ms before retry...`);
        await sleep(delay);
      }
    }
  }
  
  throw lastError;
}

// Usage example
async function getData() {
  try {
    const data = await fetchWithRetry('https://api.example.com/data');
    console.log('Successfully fetched data:', data);
  } catch (error) {
    console.error('All retries failed:', error);
  }
}

getData();

2. Creating Animation Sequences

async function animateSequence(element) {
  // Set initial state
  element.style.opacity = '0';
  element.style.transform = 'translateY(20px)';
  element.style.transition = 'all 0.5s ease-out';
  
  // Ensure element is visible
  element.style.display = 'block';
  
  // Wait one frame to ensure transition effects take effect
  await sleep(50);
  
  // Fade in animation
  element.style.opacity = '1';
  element.style.transform = 'translateY(0)';
  
  // Wait for fade in to complete
  await sleep(500);
  
  // Add emphasis effect
  element.style.transform = 'scale(1.1)';
  await sleep(200);
  
  // Restore normal size
  element.style.transform = 'scale(1)';
}

// Usage example
document.getElementById('showButton').addEventListener('click', () => {
  const notification = document.getElementById('notification');
  animateSequence(notification);
});

3. Rate Limiting API Requests

class RateLimiter {
  constructor(requestsPerSecond) {
    this.minDelayMs = 1000 / requestsPerSecond;
    this.lastRequestTime = 0;
  }
  
  async limit() {
    const now = Date.now();
    const timeElapsed = now - this.lastRequestTime;
    
    if (timeElapsed < this.minDelayMs) {
      // Calculate wait time needed
      const waitTime = this.minDelayMs - timeElapsed;
      await sleep(waitTime);
    }
    
    this.lastRequestTime = Date.now();
  }
}

// Usage example - Maximum 2 requests per second
const limiter = new RateLimiter(2);

async function fetchWithRateLimit(url) {
  await limiter.limit();
  return fetch(url).then(res => res.json());
}

// Demonstrate multiple calls
async function fetchMultipleData() {
  console.log('Start fetching data...');
  
  // These requests will be rate limited, maximum 2 per second
  const results = await Promise.all([
    fetchWithRateLimit('https://api.example.com/1'),
    fetchWithRateLimit('https://api.example.com/2'),
    fetchWithRateLimit('https://api.example.com/3'),
    fetchWithRateLimit('https://api.example.com/4')
  ]);
  
  console.log('All data fetched', results);
}

fetchMultipleData();