Rate limiting is not only a very common front-end interview question, but also a pretty common problem that you want to solve in day to day software.
Fair Game for Interviews
There are a few approaches that I can think of.
Write a rateLimit decorator that takes a function and rate limit configurations and then returns a rate-limited function. For example, a function that should only be called X times within Y minutes.
A slightly more simple one is to rate limit the function using global variables or class variables in scope. Basically you increment a counter every time you call the function, and you have a setInterval function that clears it.
What if you want to do an exponential backoff on failure?
Exponential backoff, meaning wait 1, 2, 4, 8ms every time you encounter failure, and then to reset on success. Well now you have to track 2 pieces of state. On failure, you can clear the interval, queue all batched requests, and call setTimeout, where the wait time is tracked via a global or class function. This is actually reasonably complicated, and will probably require some code to demonstrate.
Here's a simplified example I found: https://gist.github.com/mattheworiordan/1084831
In Practice
In practice, you'd only want to do this if you have some kind of polling mechanism that requires an exponential backoff, or you'd more likely want to disable user action until the request returns. If you're ever in the situation where you're simultaneously firing off hundreds of requests, you might want to reconsolidate your API. But short of that...
Today I found this gem that actually works quite well in practice.
Promise.resolve(myArray).map(myfunction, {concurrency: 3});
This will basically enable you rate-limit iterating over a collection of XHRs and sending them out 3 at a time. The number of outstanding unresolved promises is configurable via the concurrency option. Such a gem. =)