Сегодня большинство приложений управляется API. Независимо от того, создаете ли вы прогноз погоды, финансовый тикер, оповещение о спортивных результатах или переводите на местный язык, вам потребуется подключить сторонние API для доступа к необходимым данным.
API обычно измеряются, а потребление ограничивается ограничением скорости. API с ограничением скорости определяет скорость API. Обычно это выражается в количестве запросов, сделанных за определенный период времени; например, скорость API котировок цен на акции API составляет 100 в секунду, что означает, что вы можете делать только 100 вызовов в секунду.
Механизм стимуляции должен справляться с разрывом между скоростью запросов приложений и скоростью принятия API.

Настройка сценария
Предположим, мы хотим получить прогноз погоды для всех 19000 (приблизительно) почтовых индексов (PIN) в Индии. Один запрос может привести только к предсказанию одного почтового индекса, а максимальная частота вызовов API составляет 50 per second.
ОЧЕВИДНО, мы не можем выполнить 19000 запросов одновременно для получения данных. Нам нужно создать механизм для запросов в темпе.
В этом посте показано создание Pacer (на машинописном языке), который принимает все запросы на пин-коды и обращается к API с соответствующей скоростью. И браузер, и узел будут совместимы с кодом.
Понимание механизма стимуляции
Если нам нужно выполнить 19000 запроса (1 запрос за один вызов) за один вызов, мы храним запросы в памяти и берем 50 из них, выполняем их в следующую секунду, берем следующие 50 и так далее. По сути, он ограничивает запросы, не отклоняя их по максимальному лимиту.
Создание интерфейса
Логика стимуляции вполне может содержаться внутри класса. Лучше всего разделить логику вызова API и логику стимуляции. Затем темп может применяться в различных контекстах.
Интерфейс кардиостимулятора
class Pacer принимает запросы и обрабатывает их в заданном темпе. Запрос — это самоисполняемый код для его выполнения, и Pacer решает, когда запускать этот код.
interface Request<T> {
(): Promise<T>;
}
class Pacer<T> {
private ratePerSecond: number;
constructor(ratePerSecond: number) {
this.ratePerSecond = ratePerSecond;
}
pace(request: Request<T>): Promise<T> {
// implementation pending
return request();
}
}
Использование кардиостимулятора
Чтобы использовать Pacer, мы должны создать его экземпляр с требуемой скоростью. После этого можно использовать метод pace для добавления запросов.
let pacer = new Pacer<Axios.Response>(50);
let resultPromises = [];
for(let pinCode of pinCodes) {
resultPromises.push(pacer.pace(() => $axios.get(`https://api.weather.org/weather/${pinCode}`));
}
let responses = await Promise.all(results);
Внедрение темпа
Функционально правильной базовой реализацией метода темпа может быть:
При использовании приведенной выше реализации метод pace будет выполнять запрос сразу после получения, аналогично коду без стимуляции. Таким образом, мы должны пойти дальше.
Микропакеты
Запросы должны быть объединены в пакеты и выполняться один раз в секунду для надлежащей реализации. Этот метод называется микропакетной обработкой: Меньшая партия, частое выполнение. Нам нужна очередь и исполнитель для контролируемого выполнения запросов.
Очередь
Запрос будет поставлен в очередь, как только будет получен. Нам также нужно вернуть обещание результата запроса. Но мы не можем выполнить обещание без выполнения запроса.
Прокси-обещание
Будет возвращено Proxy Promise, которое зафиксирует результат запроса при выполнении. Нам нужно сохранить его разрешение и отклонить ссылки вместе с запросом.
Исполнение
Надежным выбором дизайна является сохранение выполнения запроса в отдельной функции, которая выполняет несколько запросов в очереди. Теперь нам нужно работать над тем, чтобы запускать его каждую секунду.
setTimeout() является разумной конструкцией для использования, чем setInterval(), так как с setTimeout мы можем контролировать следующее выполнение.
Логика планирования
- Когда запрос принят, он может быть обработан немедленно или с задержкой в несколько миллисекунд, если выполнение не запланировано.
- На стороне выполнения после запуска запросов мы проверяем размер очереди для планирования следующего выполнения с задержкой
1s.

Реализация работает, если запросы выполняются в течение одной секунды; вряд ли это так в реальном мире. Чтобы сделать его более эффективным, мы должны отслеживать количество обрабатываемых запросов и соответственно корректировать темп.
Полный код доступен по адресу:
Что дальше?
Это практическая реализация. Другой вариант — включить механизм повторной попытки или отказа. Я еще не рассматривал возможность реализации этой функции; Буду признателен за ваши отзывы по улучшению.