JAVASCRIPT

Client-Side API Rate Limiting with a Request Queue

Implement effective client-side API rate limiting using a JavaScript request queue to prevent exceeding server-side limits and ensure a smoother integration experience for your users.

class ApiRateLimiter {
  constructor(rateLimitMs = 1000) { // Default to 1 request per second
    this.rateLimitMs = rateLimitMs;
    this.requestQueue = [];
    this.lastRequestTime = 0;
    this.isProcessing = false;
  }

  // Method to add a new request to the queue
  async enqueueRequest(requestFn) {
    return new Promise((resolve, reject) => {
      this.requestQueue.push({ requestFn, resolve, reject });
      this.processQueue();
    });
  }

  // Process the queue
  async processQueue() {
    if (this.isProcessing || this.requestQueue.length === 0) {
      return;
    }

    this.isProcessing = true;
    const now = Date.now();
    const timeSinceLastRequest = now - this.lastRequestTime;
    const delay = Math.max(0, this.rateLimitMs - timeSinceLastRequest);

    await new Promise(res => setTimeout(res, delay));

    const { requestFn, resolve, reject } = this.requestQueue.shift();
    this.lastRequestTime = Date.now();

    try {
      const result = await requestFn();
      resolve(result);
    } catch (error) {
      reject(error);
    } finally {
      this.isProcessing = false;
      // Immediately try to process the next item if available
      if (this.requestQueue.length > 0) {
        this.processQueue();
      }
    }
  }
}

// --- Example Usage ---
const apiLimiter = new ApiRateLimiter(500); // Max 2 requests per second

const mockApiCall = (id) => {
  return new Promise(resolve => {
    const duration = Math.random() * 500 + 100; // Simulate network latency
    setTimeout(() => {
      console.log(`Request ${id} completed at ${Date.now() % 10000}ms`);
      resolve(`Data for ${id}`);
    }, duration);
  });
};

const makeLimitedCall = async (id) => {
  try {
    const data = await apiLimiter.enqueueRequest(() => mockApiCall(id));
    console.log(`Handled response for ${id}: ${data}`);
  } catch (error) {
    console.error(`Error for ${id}: ${error.message}`);
  }
};

console.log('Starting limited API calls...');
for (let i = 0; i < 10; i++) {
  makeLimitedCall(`call-${i}`);
}
console.log('All calls enqueued.');
How it works: This JavaScript snippet implements a client-side API rate limiter using a queue. The `ApiRateLimiter` class ensures that API requests are not made faster than a specified `rateLimitMs`. Requests are added to an internal queue, and the `processQueue` method asynchronously executes them, introducing a delay between each call if necessary to adhere to the rate limit. This helps prevent exceeding server-side rate limits, reducing 429 Too Many Requests errors and ensuring smoother application behavior.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs