Skip to content Skip to sidebar Skip to footer

How To Get The Number Of Pending Promises?

I'm trying to create a function which sends HTTP requests with the following logic: If there are 5 or more ongoing requests, the next request has to be postponed until one of them

Solution 1:

Here is a way to do it, where there is no need for an interval timer. It uses a queue of functions to call when the next HTTP response arrives (which makes the number of pending requests to come below 5):

var pending = 0;
var queue = [];

functionget(url){
    returnnewPromise (function(resolve,reject){
        functionloop(retries = 3) {
            var xhttp = newXMLHttpRequest();
            xhttp.open("GET",url,true);
            xhttp.onload = function(){
                pending--;
                if (xhttp.status == 200){
                    resolve(JSON.parse(xhttp.response));
                }
                elseif (retries > 0) {
                    // retry by automatically relaunching the request:loop(retries-1);
                } else {
                    // give upreject(xhttp.statusText); // correct your spelling!
                }
                if (pending < 5 && queue.length) {
                    // extract and execute the first of the queued actions:
                    queue.shift()();
                }
            };
            xhttp.onerror= function(){
                reject(xhttp.statusText); // correct your spelling
            };
            xhttp.send()
            pending++;
        }
        if (pending >= 5) {
            // Push the call we want to make for later execution in a queue:
            queue.push(loop);
        } else {
            loop(); // try at the most 3 times
        }
    });
}

Here is a snippet with a fake HTTPRequest object in order to simulate both the delay for when there are more than 5 pending requests, and a request that produces an error. All requests take 1 second to get a response, although the last one will produce an error status and will be retried 3 times, and as a consequence its promise only resolves after 3 seconds:

// Overwrite the real XMLHttpRequest with a dummy one, just for this snippet (skip this in your code!):functionXMLHttpRequest() {
    this.open = function(_, url) {
        this.status = url.indexOf('fail') > -1 ? 201 : 200;
        this.response = JSON.stringify({text: 'Response from ' + url});
        this.statusText = this.status == 200 ? 'OK' : 'Error status from ' + url;
    };
    this.send = function () {
        setTimeout(this.onload.bind(this), 1000);
    }.bind(this);
}

var pending = 0;
var queue = [];

functionget(url){
    returnnewPromise (function(resolve,reject){
        functionloop(retries = 3) {
            var xhttp = newXMLHttpRequest();
            xhttp.open("GET",url,true);
            xhttp.onload = function(){
                pending--;
                if (xhttp.status == 200){
                    resolve(JSON.parse(xhttp.response));
                }
                elseif (retries > 0) {
                    // retry by automatically relaunching the request:loop(retries-1);
                } else {
                    // give upreject(xhttp.statusText); // correct your spelling!
                }
                if (pending < 5 && queue.length) {
                    // extract and execute the first of the queued actions:
                    queue.shift()();
                }
            };
            xhttp.onerror= function(){
                reject(xhttp.statusText); // correct your spelling
            };
            xhttp.send()
            pending++;
        }
        if (pending >= 5) {
            // Push the call we want to make for later execution in a queue:
            queue.push(loop);
        } else {
            loop(); // try at the most 3 times
        }
    });
}

// Example series of calls to illustrate the effect of more than 5 simultanious requests// and the 3 retries for an error producing request:console.log('start');
get('example.com?1').then( function(obj) { console.log(obj.text) });
get('example.com?2').then( function(obj) { console.log(obj.text) });
get('example.com?3').then( function(obj) { console.log(obj.text) });
get('example.com?4').then( function(obj) { console.log(obj.text) });
get('example.com?5').then( function(obj) { console.log(obj.text) });
get('example.com?6').then( function(obj) { console.log(obj.text) });
get('example.com?7').then( function(obj) { console.log(obj.text) });
get('example.com?fail').catch( function(msg) { console.log(msg) });
.as-console-wrapper { max-height: 100%!important; top: 0; }

Solution 2:

Your question is a bit unclear but let me try to give it a shot.

You can not get pending promises, you need to store them (or a number of them) somewhere.

Regarding the part about 5 max requests:

What you're trying to do is to throttle (i.e. rate limit) the requests. It's a bit advanced topic, a naive implementation could do a solution like this:

  1. every time you create a request, you increment some variable, and when it finishes (successful or not), you decrement it (finally)
  2. if there's a request over the limit, you put it in a queue to be processed later.
  3. periodically (setInterval) you check the size of the queue, and if it is non-empty and there's fewer than 5 outgoing requests, you take an item from the queue and do HTTP request

Instead of setInterval you can use this kind of check also when you resolve/reject one of the requests - and then use setTimeout to schedule a check (because it doesn't make sense to check if nothing happened recently).

var numberOfPendingRequests = 0;
var overLimitQueue = [];

functionget(url) {
    var getPromise = newPromise(function(resolve, reject) {
        if (numberOfPendingRequests >= 5) {
            overLimitQueue.push({
                url: url,
                resolve: resolve,
                reject: reject
            });
            return;
        } else{
            numberOfPendingRequests++;
            ...
        }

    });
    getPromise.finally(function(){
        numberOfPendingRequests--;
    })
    return getPromise;
}

setInterval(function(){
    if (numberOfPendingRequests  < 5 && overLimitQueue.length > 0) {
        // process entries in the queue
    }
}, 1000);

Anyway this kind of code is rather advanced and you might be better off using someone else's library instead of doing it yourself.

Have a look at this library for instance:

https://github.com/remy/promise-throttle

Parts of the code that are doing a request could be extracted into smaller helper functions, and in the code for redoing the call, or processing queue elements, you'd use those helper methods. You might need to pass around resolve and reject functions between the helper method calls.

Post a Comment for "How To Get The Number Of Pending Promises?"