Rate Limiting in JavaScript: How Not to Let Your API Crash

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Rate limiting and throttling in JavaScript: Protection and Performance

\n\n

Have you ever wondered why, after a couple of dozen quick clicks on the "Submit" button, your favorite service suddenly stops responding? Or why some sites ask you to "wait 30 seconds" before resubmitting a form? The answer lies in two powerful mechanisms that save the backend from overload and users from "bugs": rate limiting and throttling.

\n\n

In this article, we'll look at how to apply these techniques in vanilla JavaScript and Node.js. You'll learn how throttle differs from debounce, how to write a simple rate limiter for an API, and why your website will run faster. Let's go!

\n\n

What is rate limiting and why is it needed?

\n\n

Rate limiting is a protective mechanism that limits the number of requests from a client (or IP address) within a specific time period. Imagine a barrier: a car can pass, but only once every 10 seconds.

\n\n

Where is this applied?

\n
    \n
  • Protecting APIs from DDoS attacks and spam.
  • \n
  • Preventing server overload from mass requests.
  • \n
  • Controlling resource usage in paid APIs (e.g., 100 requests per hour).
  • \n
  • Protection against "infinite loop" errors on the client.
  • \n
\n\n

Unlike throttling, which smooths out the request flow, rate limiting is a hard wall: "Stop, you've exceeded the limit."

\n\n

Throttling vs Debounce: The Main Difference

\n\n

Throttling and debounce are often confused. Let's set the record straight.

\n\n
    \n
  • Throttle — ensures a function is called no more than once every N milliseconds. Imagine a water faucet: you turn it on, and water flows at a constant rate, even if you jiggle the handle faster.
  • \n
  • Debounce — delays the function call until N milliseconds have passed since the last event. Ideal for autocomplete search: while the user is typing, no request is sent.
  • \n
\n\n

In the context of rate limiting, we are interested in throttle — we want to control the frequency, not delay requests.

\n\n

Simple Rate Limiter in JavaScript

\n\n

Let's write our own rate limiter implementation in Node.js. It will remember the time of the last request from each user and block requests that are too frequent.

\n\n
class RateLimiter {\n  constructor(limit, windowMs) {\n    this.limit = limit;          // Maximum requests\n    this.windowMs = windowMs;    // Time window in ms\n    this.requests = new Map();   // Storage: userId -> [timestamps]\n  }\n\n  allow(userId) {\n    const now = Date.now();\n    const userRequests = this.requests.get(userId) || [];\n    \n    // Remove outdated entries\n    const recentRequests = userRequests.filter(\n      ts => now - ts < this.windowMs\n    );\n    \n    if (recentRequests.length >= this.limit) {\n      console.log(`Rate limit exceeded for ${userId}`);\n      return false;\n    }\n    \n    recentRequests.push(now);\n    this.requests.set(userId, recentRequests);\n    return true;\n  }\n}\n\n// Usage\nconst limiter = new RateLimiter(5, 60000); // 5 requests per minute\n\n// Simulate requests\nfor (let i = 0; i < 10; i++) {\n  setTimeout(() => {\n    const allowed = limiter.allow('user123');\n    console.log(`Request ${i+1}: ${allowed ? '✅ Allowed' : '❌ Blocked'}`);\n  }, i * 2000); // Every 2 seconds\n}
\n\n

This code is great for educational purposes, but in production it's better to use ready-made solutions (e.g., express-rate-limit for Express or rate-limiter-flexible).

\n\n

Throttling on the Client: Protection Against Rapid Clicks

\n\n

Often the problem occurs on the client side: a user clicks the "Submit" button several times, and requests are sent in parallel. R

Blogs

Book Recommendations