SaeX
SaeX

Reputation: 18761

Only execute next AJAX call if previous one is done

I'm generating PDFs in the background through an AJAX call. Generating the PDF takes some time (about a second or so).

The below works fine, but the problem is that I run out of memory. Hence I'd like to only start the computation (i.e. only issue the AJAX call) when the previous AJAX call is done.

I've played around with async: false but that freezes my page, which is unwanted behavior (and the use of async is deprecated anyhow).

My code:

$("div[data-myid]").each(function(){

    var myid= $(this).data('myid');
    var my_div = $(this);

    $.ajax({
        url: "/my_ajax/" + myid + "/",
    }).done(function (data) {
        my_div.html(data.message + ' <a href="' + data.url +  '">Download</a>');
    });

});

HTML:

<table>
    <tr>
        <td><div id="div_260" data-myid="260">Queued..</div></td>
    </tr>
    <tr>
        <td><div id="div_259" data-myid="259">Queued..</div></td>
    </tr>
</table>

Note the table is dynamically generated and generally contains 100+ rows.

Any idea on how to best approach this?

Upvotes: 2

Views: 2044

Answers (2)

Rahul Patel
Rahul Patel

Reputation: 5244

Next ajax should be fire only after current ajax call get finished. Below code will help you to achieve it.

Steps to achieve it.

  • create an array and push the DOM object in an array for all divs.
  • Create a function for ajax call and recursively call it for all the div.
  • doAjax function will be called in ajax success function. Therefore, Next ajax will be fired only after current get finished.

This is my code:

 <script type="text/javascript">    

    var elementArray = [];

    //Code to push all divs in elementArray
    $(document).ready(function(){
        $("div[data-myid]").each(function () {
            elementArray.push($(this));
        });
        // First ajax call.
        doAjax(0);
    });

    //Function to ajax fire
    function doAjax(arrCount) 
    {
        var myid = elementArray[arrCount].data("myid");
        var my_div = elementArray[arrCount];

        $.ajax({
            url: "/my_ajax/" + myid + "/",
            type:"POST",
            dataType:"json",
            success: function (data) {              
                if (arrCount < elementArray.length-1) {
                {
                    my_div.html(data.message + ' <a href="' + data.url +  '">Download</a>');
                    arrCount++;
                    //Next ajax call when current ajax call has been finished.
                    doAjax(arrCount);
                }         
            }
        });
    }

</script>

Upvotes: 6

Marko Mackic
Marko Mackic

Reputation: 2333

Maybe like this :

function postponeAjax(index,element){
     var myid= $(element).data('myid');
     var my_div = $(element);
     setTimeout(function(){
        $.ajax({
          url: "/my_ajax/" + myid + "/",
        }).done(function (data) {
          my_div.html(data.message + ' <a href="' + data.url +  '">Download</a>');
        });
      },index*2000);

    }
    $("div[data-myid]").each(function(index,element){ // if I remember well
       postponeAjax(index,element)   
    });

This is kind of hacky solution but I think it should work :) Here is a replit with basic example using for loop https://repl.it/CfJA. The 2000 delay, you modify it to fit creation time of pdf with some tolerance of + 1 second :)

EDIT :

There is this handy function that is called when last ajax call is completed

$(document).ajaxStop(function() {
  // place code to be executed on completion of last outstanding ajax call here
});

So we can do something like this:

   var number_of_elements =  $("div[data-myid]").length;
   var current_index = 0;
   var myid, mydiv;

   function doAjax(){
        mydiv = $("div[data-myid]:eq("+current_index+")"))
        myid = mydiv.data('myid');
        $.ajax({
            url: "/my_ajax/" + myid + "/",
        }).done(function (data) {
           my_div.html(data.message + ' <a href="' + data.url +  '">Download</a>');
        });
        current_index++;
   }
   //repeat until there is no more elements
   $(document).ajaxStop(function(){
      if(current_index < number_of_elements){
         doAjax();
      }
   });
   //init the sequence
   doAjax();

I have not tested this, so notify me if it does not work :D

Upvotes: 1

Related Questions