you_are_enot
@you_are_enot
Пограммист любитель

Как ограничить максимальное количество параллельных запросов?

У меня есть массив, например, из 2000 url на которые нужно отправить запросы, собрать ответы в новый массив и после прохода по всем ссылкам вернуть результат (с помощью Promise.all). При этом нужно, чтобы одновременно выполнялось не более 20 запросов. То есть оправляется первые 20 запросов, как только по одному и них приходит ответ, отправляется следующий.
  • Вопрос задан
  • 1391 просмотр
Решения вопроса 1
@Bapen1k
Работает!!!!))
Пришлось писать свой Promise.race, который возвращает индекс решенного промиса в массиве.

В конструктор передается лимит одновременных запросов, который не будет превышать функция. Функция делает сразу N запросов, где N это лимит, как только разрешается один промис делается еще один запрос.

const promiseRace = promises => (
  new Promise((fulfil, reject) => {
    promises.forEach((promise, index) => {
      promise.then(data => fulfil({ data, index }), reject);
    });
  })
);

class Fetcher {
  constructor(maxConnections = 20) {
    this.maxConnections = maxConnections;
  }

  async request(urls, options = {}) {
    const responsePromises = [];

    for (const url of urls) {
      if (responsePromises.length >= this.maxConnections) {
        const { data: response, index } = await promiseRace(responsePromises);
        responsePromises.splice(index, 1);
      }
      responsePromises.push(fetch(url, options));
    }

    return Promise.all(responsePromises);
  }
}

// test
(async () => {
  try {
    const fetcher = new Fetcher(2); // лимит 2
    const urls = [];

    for (let i = 0; i < 200; i++) {
      urls.push(`/api/user/${i}`);
    }

    const responses = await fetcher.request(urls);
    console.log('end');
  } catch (e) {
    console.error(e);
  }
})();
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 4
inoise
@inoise
Solution Architect, AWS Certified, Serverless
Если скрипт запускается в одном экземпляре то просто каунтер в памяти
Ответ написан
Комментировать
@rPman
Выдавайте новый запрос на каждое следующее подключение на дисконнекте или завершении загрузки (и ошибках) предыдущего, а при запуске всего скрипта поставьте запуск 20 загрузок. Никакой каунтер тогда не понадобится.
Ответ написан
Комментировать
@Azperin
Дилетант
Можно попробовать чтото вроде такого
var originalArr = [...];
var firstArr = originalArr.slice(0, 19);
var restArr = originalArr.slice(19);
firstArr.forEach(fetchNext);

function fetchNext(url) {
	if (!url) {
		return;
	};
	
	fetch(url).then().catch().finaly(() => {
		fetchNext(restArr.shift());
	});
};
Ответ написан
Комментировать
@Gleb_A
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы