最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to do sequential asynchronous ajax requests with given number of streams - Stack Overflow

programmeradmin1浏览0评论

I need to make sequential asynchronous ajax requests with limited streams. As of now I am allowed to occupy only one stream on web server so I can only do one ajax request at time.

I have following function which helps me when I am allowed to use only one stream at a time.

function initiateChain() {
    var i = 0;
    var tasks = arguments;
    var callback = function () {
      i += 1;
      if (i != tasks.length) {
        tasks[i](callback); //block should call callback when done otherwise loop stops
      }
    }
    if (tasks.length != 0) {
      tasks[0](callback); //initiate first one
    }
  }

Say if I have three ajax helper functions

 function getGadgets(callback) {
         //ajax call
         callback(); // I call this in complete callback of $.ajax
 }

 function getBooks(callback) {
         //ajax call
         callback(); // I call this in complete callback of $.ajax
 }

 function getDeals(callback) {
         //ajax call
         callback(); // I call this in complete callback of $.ajax
 }

following call ensures that no more than 1 ajax request is made from this client

initiateChain(getGadgets, getBooks, getDeals);

Now I need to enhance initiateChain to support arbitrary number of streams. Say I am allowed to use 2 or n number of streams I would like to know ideas to do so without changing ajax helper functions getGadgets, getDeals, getDeals.

In short, I have a set of functions, N, in this case getGadgets, getDeals and getDeals(|N|=3) that each need a connection to the web server. Currently, I can only execute one request at a time, so initiateChain function calls the three methods in sequence. If I had access to M connections, I would like to execute |N| functions in parallel (up to a maximum of M).

I need to make sequential asynchronous ajax requests with limited streams. As of now I am allowed to occupy only one stream on web server so I can only do one ajax request at time.

I have following function which helps me when I am allowed to use only one stream at a time.

function initiateChain() {
    var i = 0;
    var tasks = arguments;
    var callback = function () {
      i += 1;
      if (i != tasks.length) {
        tasks[i](callback); //block should call callback when done otherwise loop stops
      }
    }
    if (tasks.length != 0) {
      tasks[0](callback); //initiate first one
    }
  }

Say if I have three ajax helper functions

 function getGadgets(callback) {
         //ajax call
         callback(); // I call this in complete callback of $.ajax
 }

 function getBooks(callback) {
         //ajax call
         callback(); // I call this in complete callback of $.ajax
 }

 function getDeals(callback) {
         //ajax call
         callback(); // I call this in complete callback of $.ajax
 }

following call ensures that no more than 1 ajax request is made from this client

initiateChain(getGadgets, getBooks, getDeals);

Now I need to enhance initiateChain to support arbitrary number of streams. Say I am allowed to use 2 or n number of streams I would like to know ideas to do so without changing ajax helper functions getGadgets, getDeals, getDeals.

In short, I have a set of functions, N, in this case getGadgets, getDeals and getDeals(|N|=3) that each need a connection to the web server. Currently, I can only execute one request at a time, so initiateChain function calls the three methods in sequence. If I had access to M connections, I would like to execute |N| functions in parallel (up to a maximum of M).

Share Improve this question edited Feb 11, 2013 at 9:33 harsha asked Feb 11, 2013 at 5:03 harshaharsha 9631 gold badge13 silver badges28 bronze badges 2
  • 1 What exactly is your question? – jfriend00 Commented Feb 11, 2013 at 5:13
  • As I mentioned I have a set of functions, N, in this case getGadgets, getDeals and getDeals(|N|=3) that each need a connection to the web server. Currently, I can only execute one request at a time, so initiateChain function calls the three methods in sequence. If I had access to M connections, I would like to execute |N| functions in parallel (up to a maximum of M). – harsha Commented Feb 11, 2013 at 7:57
Add a comment  | 

3 Answers 3

Reset to default 16

If you're using jQuery then you can use its .queue method to queue up your ajax calls and then execute them in sequence. To run multiple sequences, you can wrap the initial dequeue in a loop.

function add_api_call_to_queue(qname, api_url) {
    $(document).queue(qname, function() {
        $.ajax({
            type     : 'GET',
            async    : true,
            url      : api_url,
            dataType : 'json',
            success  : function(data, textStatus, jqXHR) {
                // activate the next ajax call when this one finishes
                $(document).dequeue(qname);
            }
        });
    });
}

$(document).ready(function() {

    var queue_name       = 'a_queue';
    var concurrent_calls = 2;

    // add first AJAX call to queue
    add_api_call_to_queue(queue_name, '/example/api/books');

    // add second AJAX call to queue
    add_api_call_to_queue(queue_name, '/example/api/dvds');

    // add third AJAX call to queue
    add_api_call_to_queue(queue_name, '/example/api/shoes');

    // start the AJAX queue
    for (i=0;i<concurrent_calls;i++) {
        $(document).dequeue(queue_name);
    }

})

As long as your callbacks are all synchronous this should work for you, if not put you on the right track

var initiateChain = function () {

    var args = arguments,
        index = 0,
        length = args.length,
        process = function ( index ) {

            if ( index < length ) {
                $.ajax({
                    url: '/example.php',
                    complete: function () {
                        // Callbacks get run here
                        args[ index ];
                        process( ++index );
                    }

                });
            }


        };

    if ( length ) {
        process( 0 );
    }

};

initiateChain( getGadgets, getDeals, getDeals );

Thanks @James, I got clue from what you edited for length. As such the calls are async ajax requests. So the idea is in creating M number of async calls upfront. Then they will continue those many as and when each one is complete.

I did experiment with nodejs and following initiateChain works as intended

var calls = [];

function initiateChain() {
    var i = 0;
    var maxSteams = 2;
    var tasks = arguments;
    var callback = function () {
      i += 1;
      if (i < tasks.length) {
        tasks[i](callback); //block should call callback when done otherwise loop stops
      }
    }
    if (tasks.length) {
      i = ((tasks.length > maxSteams) ? maxSteams : tasks.length) - 1;
      for (var j = 0; j < maxSteams; j+=1) {
        if (j < tasks.length) {
          tasks[j](callback); //initiate first set
        } else {
          break;
        }
      }
    }
}

//test methods
for(var k = 0; k < 8; k+=1 ) {
  calls[k] = (function (message, index) {
    return function (callback) {
      var ts = new Date().getTime();
      console.log(message + " started - " + ts);
      setTimeout(function() {
        ts = new Date().getTime();
        console.log(message + " completed - " + ts);
        callback();
      }, index * 1000);
    };
  })("call" + (k+1), (k+1))
}

initiateChain(calls[0], calls[1], calls[2], calls[3], 
    calls[4], calls[5], calls[6], calls[7]);

In my experiment I got following results

call1 started - 1360580377905
call2 started - 1360580377926

call1 completed - 1360580378937
call3 started - 1360580378937

call2 completed - 1360580379937
call4 started - 1360580379937

call3 completed - 1360580381945
call5 started - 1360580381945

call4 completed - 1360580383946
call6 started - 1360580383946

call5 completed - 1360580386959
call7 started - 1360580386959

call6 completed - 1360580389950
call8 started - 1360580389950

call7 completed - 1360580393972

call8 completed - 1360580397959
发布评论

评论列表(0)

  1. 暂无评论