timj
timj

Reputation: 23

$.ajax and .each in JQuery, with MVC, isn't asynchronous

my Ajax calls don't seem to be asynchronous when wrapped inside a .each loop, instead they seem to wait for each to finish before calling the next one ..

MVC C#:

   [HttpPost]
    public JsonResult DoActionGetNextStep(JSONSubmission Submission)
    {
        SomeStruct body = new SomeStruct();
        DateTime start = DateTime.Now;
        try
        {
        System.Threading.Thread.Sleep(5000);
        body.html= "There, done";
        }
        catch (Exception e)
        {
        body.html= "There was an error: "+e.Message;
        }
        TimeSpan s = DateTime.Now - start;
        ast.Html = body.html+ "<p> c# took " +s.Seconds +"s</p>";
        return Json(body);
    }  

JQuery:

function DoActions(targets) {
$(targets).each(function () { DoAction($(this)); });
}

function DoAction(target) {
var parent = $(target).parents('div.actionReplaceable');
var JSONSubmission = { Data : "somedata" };
var Submission = JSON.stringify(JSONSubmission, null, 2);

$.ajax({
    type: 'POST',
    url: '/Main/DoActionGetNextStep',
    data: Submission,
    async: true,
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    success: function (Result) {
        var html = Result.html;
        $(parent).html(html);
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) {
        $(parent).html("JQuery Error: " + textStatus + "\n" + errorThrown);
    }
});
}

This ends up taking 25 seconds for 5 elements, each of them reporting that their call took 5 seconds. I thought ajax calls were asynchronous, so this operation should take 5 seconds total? Both server and browser are running on my localhost. Can anyone spot what I'm missing?

Upvotes: 2

Views: 912

Answers (2)

Tomalak
Tomalak

Reputation: 338426

Your requests should be asynchronous. Check with console.log in the appropriate places to see when things happen.

$(targets).each(DoAction);

function DoAction() {
  var $parent = $(this).parents('div.actionReplaceable'),
      JSONSubmission = { Data : "somedata" };

  console.log("sending request for " + this-id);

  $.ajax({
    type        : 'POST',
    url         : '/Main/DoActionGetNextStep',
    data        : JSON.stringify(JSONSubmission, null, 2),
    contentType : 'application/json; charset=utf-8',
    success     : function (Result) {
      console.log("received response for " + this-id);
      $parent.html(Result.html);
    },
    error       : function (XMLHttpRequest, textStatus, errorThrown) {
      console.log("received error for " + this-id);
      $parent.html("JQuery Error: " + textStatus + "\n" + errorThrown);
    }
  });
}
  • There is no need for a target parameter. jQuery sets this correctly for callback functions.
  • Once you got rid of the target parameter you just need to pass the function reference to .each().
  • Unless the return type is JSON (seems to be HTML here), setting dataType: 'json' is wrong.
  • setting async: true is superfluous unless you configured the global Ajax options to be async: false. Which I hope you did not.

Upvotes: 0

Codo
Codo

Reputation: 79033

There are two reasons why Ajax calls aren't processed in parallel:

  1. Most browsers limit this, either because they only use two connections to each site they contact or because they explicitly limit concurrent Ajax calls.

  2. If you access the session state in an ASP.NET application (MVC or not), you'll also run into an exclusive lock that causes parallel connections to wait. For MVC, there's an attribute to indicate that your controller action only requires read-only access to the session state to work around that.

Upvotes: 2

Related Questions