Как в JavaScript осуществляется синхронизация нескольких параллельных запросов?

У нас есть 10 запросов, но одновременно мы можем выполнять только 3 из них. <br/> Как организовать выполнение этих запросов в цикле, чтобы одновременно запускать 3 запроса, и после завершения каждого из них запускать новый, при этом объединяя все результаты в один итоговый вывод?
  • 10 октября 2024 г. 8:14
Ответы на вопрос 2
Для решения задачи с ограниченным количеством одновременно выполняемых параллельных запросов в JavaScript можно использовать асинхронные функции и Promise. Мы можем создать очередь из промисов, чтобы управлять выполнением 3 параллельных запросов.

Вот пример кода, который демонстрирует, как это можно реализовать:

```javascript
async function performRequest(id) {
    // Имитация асинхронного запроса (например, fetch).
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log(`Запрос ${id} выполнен`);
            resolve(`Результат запроса ${id}`);
        }, Math.random() * 2000); // Задержка от 0 до 2 секунд.
    });
}

async function limitConcurrentRequests(requests, limit) {
    const results = [];
    const executing = [];

    for (let i = 0; i < requests.length; i++) {
        const request = requests[i];

        const p = performRequest(request).then(result => {
            results[i] = result; // Сохранение результата по индексу
        });

        executing.push(p);

        if (executing.length >= limit) {
            // Ждем завершения любого запроса
            await Promise.race(executing);
            // Убираем завершившийся запрос из executing
            executing.splice(executing.findIndex(p => p === Promise.race(executing)), 1);
        }
    }

    // Ждем завершения оставшихся запросов
    await Promise.all(executing);
    return results;
}

// Пример использования
const requests = Array.from({ length: 10 }, (_, i) => i + 1); // Массив запросов с id от 1 до 10
limitConcurrentRequests(requests, 3).then(results => {
    console.log('Все запросы завершены:', results);
});
```

### Объяснение кода:

1. **Функция `performRequest(id)`**: Это функция, которая имитирует асинхронный запрос (например, к API). Здесь используется `setTimeout`, чтобы создать случайную задержку выполнения.

2. **Функция `limitConcurrentRequests(requests, limit)`**: 
   - `requests`: массив идентификаторов запросов.
   - `limit`: максимальное количество параллельных запросов.
   - В этой функции мы создаем массив `results` для хранения результатов и массив `executing` для отслеживания текущих выполняемых запросов.

3. **Цикл `for`**:
   - Для каждого запроса создается промис `p`, который выполняет `performRequest`.
   - Мы добавляем этот промис в массив `executing`.
   - Если количество выполняющихся промисов достигает лимита, мы ждем завершения любого из них с помощью `Promise.race()`, а затем удаляем его из массива `executing`.

4. **`Promise.all(executing)` после цикла**: После завершения цикла мы ждем окончания всех оставшихся промисов в массиве `executing`.

5. **Итог**: После завершения всех операций мы выводим результаты.

Такой подход позволяет управлять количеством одновременно выполняемых запросов, при этом результаты сохраняются и выводятся в финале.
Ты делаешь метод выполнения 'следующего запроса' (он будет смотреть список задач и исполнять первый не выполненный, либо вернет - все закончилось) асинхронным async function do_next()..., и в цикле просто вызываешь этот метод await do_next() пока не вернется все закончилось, параллельно можно запустить таймер таймаута, который завершит все невыполненное.
Похожие вопросы