Показать сообщение отдельно
  #23 (permalink)  
Старый 01.09.2021, 13:57
Аватар для Alexandroppolus
Профессор
Отправить личное сообщение для Alexandroppolus Посмотреть профиль Найти все сообщения от Alexandroppolus
 
Регистрация: 25.10.2016
Сообщений: 1,005

Сообщение от dc65k
const sendRequests = (requests, maxRequestsCount) => {
У такого подхода есть баг: если мы отправим 2 порции запросов, то они пойдут параллельно, т.е. будет в два раза больше запросов одновременно - у них ведь 2 независимые очереди.
Запилил исправленную версию, которая позволяет отправлять несколько порций. Причем, вторая порция может начать исполняться ещё до того, как завершится первая.
function createSendRequests(func, limit) {
    let reqCount = 0;
    const queue = [];
    return function (requests) {
        console.log('sendRequests for ', requests.join(','));
        if (!requests || !requests.length) {
            return Promise.resolve([]);
        }
        return new Promise((resolve) => {
            const responses = Array.from({length: requests.length});
            let curUrlInd = 0;
            let requestDone = 0;

            while (curUrlInd < requests.length && reqCount < limit) {
                makeRequest(curUrlInd);
            }

            let inQueue = curUrlInd < requests.length;
            if (inQueue) {
                queue.push(nextRequest);
            }

            function nextRequest() {
                makeRequest(curUrlInd);
                if (inQueue && curUrlInd === requests.length) {
                    inQueue = false;
                    queue.shift();
                }
            }

            function makeRequest(n) {
                reqCount++;
                curUrlInd++;
                const req = requests[n];
                console.log('request for ', req);
                func(req).then(data => {
                    console.log('response for ', req);
                    responses[n] = {
                        data
                    };
                }, (err) => {
                    responses[n] = {
                        error: err || 'error'
                    };
                }).finally (() => {
                    reqCount--;
                    if (queue.length) {
                        queue[0]();
                    }
                    requestDone++;
                    if (requestDone === requests.length) {
                        resolve(responses);
                    }
                });
            }
        });
    };
}

// ----- использование -------------------------------------

function myFetch(req) {
    return new Promise((res) => {
        setTimeout(res, 1000, 'response for ' + req);
    });
}

var sendRequests = createSendRequests(myFetch, 5);

sendRequests([
    'reqA',
    'reqB',
]).then((data) => {
    console.log('responses 1', data);
});

sendRequests([
    'req1',
    'req2',
    'req3',
    'req4',
    'req5',
    'req6',
    'req7',
]).then((data) => {
    console.log('responses 2', data);
});

sendRequests([
    'req8',
    'req9',
    'req10',
    'req11',
    'req12',
]).then((data) => {
    console.log('responses 3', data);
});
Ответить с цитированием