Amr Ayoub Amr Ayoub - 1 month ago 18
Javascript Question

ES6 promises pending requests

I'm trying to create a function which sends a http(s) request with the a logic that when You send a http(s) request. If there is 5 or more ongoing requests, you have to wait until one of them is completed then you can process next request. When the response code is not 200, you need to retry 3 times. If the response code after retrying 3 times is still not 200 then the error function should be executed.

how can i know the ongoing requests ? and wait until one of them is completed then I can process next request?

var count = 0;

function get(url) {
return new Promise(function(resolve, reject) {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", url, true);

xhttp.onload = function() {
if (xhttp.status == 200) {
resolve(JSON.parse(xhttp.response));
} else if (xhttp.status != 200 && count != 3) {
count++;

resolve(JSON.parse(xhttp.response));
} else if {
reject(xhttp.statueText):
} else(count == 3) {
reject("you have reached the maximum number of tries")
}

xhttp.onerror = function() {
reject(xhttp.statueText);

};
xhttp.send()

});
}
var promise = get("data/tweets.json);
promise.then(function(tweets) {
console.log(tweets);
};


any help would be appreciated , Thanks .

Answer

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 lead to a number of pending requests that is below 5:

var pending = 0;
var queue = [];

function get(url){
    return new Promise (function(resolve,reject){
        function loop(retries = 3) {
            var xhttp = new XMLHttpRequest();
            xhttp.open("GET",url,true);
            xhttp.onload = function(){
                pending--;
                if (xhttp.status == 200){
                    resolve(JSON.parse(xhttp.response));
                }
                else if (retries > 0) {
                    // retry by automatically relaunching the request:
                    loop(retries-1);
                } else {
                    // give up
                    reject(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!):
function XMLHttpRequest() {
    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 = [];

function get(url){
    return new Promise (function(resolve,reject){
        function loop(retries = 3) {
            var xhttp = new XMLHttpRequest();
            xhttp.open("GET",url,true);
            xhttp.onload = function(){
                pending--;
                if (xhttp.status == 200){
                    resolve(JSON.parse(xhttp.response));
                }
                else if (retries > 0) {
                    // retry by automatically relaunching the request:
                    loop(retries-1);
                } else {
                    // give up
                    reject(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; }

Comments