Dealing with concurrent Ajax requests

I'm trying to do the following:

How can I make sure that only the response to the last request sent will eventually be displayed in its target DIV ?

If I click on the link labelled Data1, then Data2, the first call must be aborted because Response1 could arrive after Response2. The problem seems to imply that I must keep track of previous requests for each target, so I can abort them whenever a new request is made.

I've written this piece of code. I'd like to know if you think this is the approach is right.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title></title>
  </head>
  <body>
    <ul>
      <li><a href="data1.htm" class="trigger" data-target="d1">Data 1</a></li>
      <li><a href="data2.htm" class="trigger" data-target="d1">Data 2</a></li>
      <li><a href="data3.htm" class="trigger" data-target="d2">Data 3</a></li>
      <li><a href="data4.htm" class="trigger" data-target="d2">Data 4</a></li>
    </ul>
    <div id="d1"></div>
    <div id="d2"></div>
    <script type="text/javascript" src="/test/jquery-1.7.1.min.js"></script>
    <script type="text/javascript">
      $(function(){
        var register = {};

        $(".trigger").on("click", function() {
          var target = $(this).attr("data-target");
          var url = $(this).attr("href");
          if (register[target] == undefined) register[target] = [];

          ajaxCall = $.get(url, function(data) { // Ajax request
            $("#" + target).html(data);
          });

          for (a in register[target]) { // Aborts existing ajax requests for this target
            register[target][a].abort();
          }
          register[target] = []; // Empty register for this target
          register[target].push(ajaxCall); // Register current ajax request

          return false;
        });

      });
    </script>
  </body>
</html>

Upvotes: 0

Views: 1676

Answers (1)

pimvdb
pimvdb

Reputation: 154948

Your idea is right in my view. However, you should not use for in to loop over an array. Also you might want to abort all calls first (just to be sure).

Actually, you're clearing the array each request and only fill it with one ajax call. In this case, it is not necessary to loop over the array, since you know it will only contain one element if the array is not empty. On the other hand, you don't know whether it will contain zero or one element, so a loop is the most concise way to abort a call if it is present.

Also, you can use .data to get data- attributes.

Lastly, you could make use of the || trick.

var target = $(this).data("target"),
    url = $(this).attr("href");

register[target] = register[target] || [];

$.each(register[target], function() {
    this.abort();
});

ajaxCall = $.get(url, function(data) { // Ajax request
    $("#" + target).html(data);
});

register[target].push(ajaxCall); // Register current ajax request

Upvotes: 2

Related Questions