user192632
user192632

Reputation: 266

Async success function being called after page redirect

This function is called after an ajax get request gets results back

function handleLogin() {
    if ($("#imalogin").length) {
        alert("Your login has expired, please log back in");
        window.location.replace("login.aspx");
    }
}

This is a function that calls it

function addEstablishments() {
    $.get(encodeURI("addEstablishment.aspx?locationCode=" + $('#locationCode').val()), function (data) {
        $("#dbCheck").html(data);
        handleLogin();
    }).done(function (){
        if ($("#duplicateEstablishment").length) {
            $("#locationCodeError").html("Location code already used")
        }
        else {
            alert("Location added");
            getEstablishments();
            hideLocationForm();
        }
    }).fail(function () { 
        alert("Failed to add location. Please try again in a few seconds"); 
        $("#locationAddressError").html("Could not confirm address"); 
    });
}

I would "expect" handleLogin to show the alert inside of it, which it does, and then redirect immediately and the rest of the code would not execute. But this is the strange land of javascript, so the alert in the .done event of addEstablishments fires as well before it redirects, so people get a message that it has been added when it has not, and they get redirected to a login page, log in and find out it was never added. So there is some obscure javascript rule that I'm not aware of or is this because I can't call handleLogin where I am, and need to call it in .done?

Upvotes: 3

Views: 1478

Answers (2)

gfullam
gfullam

Reputation: 12045

The location.replace initiates an async process

JavaScript is single-threaded, not multi-threaded, so it can only process statements sequentially (or synchronously). Contrary to some comments here, this means that two callbacks cannot be executed at the same time. One is being executed first, the other is being executed second.

The issue is that by making a location assignment, an asynchronous process has been initiated by JavaScript in the browser. The browser is now handling the location assignment: making HTTP requests and waiting for a server response before it redirects to the new location.

In the mean time, the JavaScript thread can continue executing the next callback. So, the second alert can appear before the page redirect is completed by the browser.

Define .done() conditionally inside your first callback

To redirect the page in your first success handler without your secondary done() handler executing, define it conditionally inside your first handler.

function handleLogin() {
 if ($("#imalogin").length) {
   alert("Your login has expired, please log back in");
   
   // async process initiated
   window.location.replace("login.aspx");
   
   // this returns true before the async location redirect completes
   return true; 
 } else {
   return false;
 }
}

$.get('http://jsonplaceholder.typicode.com/posts/1', function(data, status, jqxhr) {
  $("#dbCheck").html(JSON.stringify(data));
  
  // If handleLogin returns false…
  if(!handleLogin()) {
    
    // …assign second success handler.
    // (This never gets assigned if handleLogin returns true.)
    jqxhr.done(function(data) { 
      alert('second success');
    });
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<input type="text" id="imalogin" disabled /><br />
<code id="dbCheck"></code>

Upvotes: 2

ramin bakhshpour
ramin bakhshpour

Reputation: 79

you need to look at jquery documentation, you passed

function (data) {
    $("#dbCheck").html(data);
    handleLogin();
}

as $.get second argument , so it is called on ajax success, and again you have used done function with another function as it's argument.

this is from jquery documentation:

// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
  var jqxhr = $.get( "example.php", function() {
    alert( "success" );
  })
  .done(function() {
    alert( "second success" );
  })
  .fail(function() {
    alert( "error" );
  })
  .always(function() {
    alert( "finished" );
  });

Upvotes: 0

Related Questions