Subsequent Calls in Ajax

Asked

Viewed 542 times

8

I wrote a system in Web2py for a client, and he wants me to automate a procedure. I thought of using Ajax. The idea is the following:

I have a list of companies. Let’s say, 50. I want the screen to open with the list of companies and, at the top of them, have a "Start" button. When I click "Start", the page sends to the server an Ajax request asking to run a calculation for the first company. This is done because it is a heavy calculation, and leaving everything on a request would make Nginx return a timeout and the calculation would not go through.

How to update the status on the screen. Now comes my question.

After the calculation of the first company, the calculation of the second enterprise is automatically called. At the end of the second, it is called the calculation of the third, and so on, until the calculation of the other:

Empresa 1: Ok!
Empresa 2: Ok!
Empresa 3: Processando...
Empresa 4: Aguardando...
...

The idea is that I can also pass some parameters beyond the company code, as for example a date range.

How can I do this? Should I use pure Ajax or can I use a JS package for this?

  • 1

    I did not understand very well your doubt: these parameters to be passed come from where? (some input user, for example, set before he click "Start"? ) And is there any restriction regarding the solution, or is it just a matter of JS even? (It seems simple to do manually, if there is no framework in use capable of this, I do not justify introducing a new one just for this)

  • It’s pure JS. Suppose I can pass the dates using <input text>s and reading the values using jQuery, for example. The challenge is to call the procedures sequentially.

4 answers

6


I would do using async since Voce is willing to use an external library

$(function() {
  async.eachSeries($('td.usuario').toArray(), function(td, cb) {
    var $td = $(td);

    $.ajax({
        url: 'suaUrl',
    }).done(function(data) {
        cb(); //Use o objeto $td para alterar o status (.siblings('td'))
    }).fail(function() {
        cb(new Error('ops!'));
    });

  }, function(err) {
      if(err) {
          console.log('Algo deu errado...')
      }

      console.log('FIM!');
  });
});

HTML would look something like this.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/async/0.9.0/async.js"></script>

<table>
  <tr>
    <td class="usuario" data-user="101">Fulano</td>  
    <td>Aguardando...</td>  
  </tr>
  <tr>
    <td class="usuario" data-user="129">Ciclano</td>  
    <td>Aguardando...</td>  
  </tr>
  <tr>
    <td class="usuario" data-user="74">Beltrano</td>  
    <td>Aguardando...</td>  
  </tr>  
  <tr>
    <td class="usuario" data-user="2056">Asnésio</td>  
    <td>Aguardando...</td>  
  </tr>  
</table>
  • I liked it. I will implement it and I already accept it. Thanks!

  • 2

    @Ciganomorrisonmendez this solution is nice because if you want to send more than one requisicao at the same time you can change of .eachSeries for .eachLimit easily, look at the Docs!

5

Assuming that all its elements are brothers (various lis for example, or rows of a table) you can make the call ajax in the first and - when completing it - pass next pro until no more:

$("#meuid li:eq(0)").each(function processar() {
    var $this = $(this);
    var parametros = $(...)...;
    var idEmpresa = $this.data("empresa");
    $.get(url, params, function(dados) {
        // Tratar dos dados
        $this.next("li:eq(0)").each(processar); // O each se encarrega da condição de parada
    });                                         // quando o next não retornar nenhum elemento
});

Here when using :eq(0) on the dial of next, I guarantee that at most a single element will be returned. Zero if there is none, and one if there is one. The call from each is for convenience even, one could simply use a function with parameter.

  • It looks good too. I just don’t understand why you use the next whereas the each already ensures an iteration loop.

  • It’s because of the asynchronicity: if I use a each all in all, it will launch all ajax calls without waiting for the previous ones to complete. That way, only after the first one is received will he make the second request, and only on receipt of the second one will be made the third one, etc (that’s what you wanted, no?)

  • 1

    Exactly. Very interesting this solution. I’ll try this one too.

2

Normally I would make an accountant and go through the entire list until I reached the total number of companies:

var lista = $('.lista').find('li');
function calcular(loop){
    if (loop <= lista.length){
        var empresa = $('.lista').find('li:eq('+loop+')');
        $.getJSON(empresa.data('url'), function(data) {
           calcular(loop+1);
        }
    }
}
calcular(0);
  • Interesting because it uses recursiveness. But what about the performance of it? It wouldn’t be impaired in a way if the list is too large?

  • I see no performance problems as it follows the logic of calling the next request when the current one is finished, working simply as a queue.

1

Pure Ajax can solve your problem. The term varies - Cascading calls or Sequential async calls:

$.getJSON("http://example.com/jsoncall", function(data) {
        process(data);
        $.getJSON("http://example.com/jsoncall2", function (data) {
            processAgain(data);
            $.getJSON("http://example.com/anotherjsoncall", function(data) {
                processAgainAndAgain(data);
            });
        });
    });

In this case, you are responsible for ensuring the chaining in case something goes wrong.

Via Angularjs is even easier:

$q.all([asyncCall1(), asyncCall2() .....])
  • 1

    I can’t believe he’s gonna have a fixed number of companies

  • Exactly. And that number will increase.

  • @renatoargh correct, but the method process can serve as callback of a Queue.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.