Lolly
Lolly

Reputation: 36412

Race condition in JavaScript

In my web application, I have a change event defined for a textbox, which is calling a ajax method and store the textbox value into a session. I have button called "test" which is going to check the validation of the entered text in textbox, where it takes the string from session and validates.

<html>
<head>  
<script type="text/javascript">
$(document).ready(function(){    
    $("input", form).change(function() {
            //using ajax to store the text value to session
        });

    $("#validateAmt").click(function() {
            //using another ajax to check the value stored in session
        });
});
</script>
</head>
<body>
  <input type="text" id="amount">
  <input type="button" id="validateAmt" value="validate"/>
</body>
</html> 

But sometimes what happens is when I enter something in textbox and without clicking anywhere outside, if I click on the "test" button directly, where button event triggers first (which validates with old value in session) and textbox change event triggers. So currently I thought of using boolean flags in JavaScript and to call first textbox change event. Is there any efficient or good solution for this kind of scenario ? And also how will the methods executed ? Will it occur parallely or sequently one after the other ?

Upvotes: 0

Views: 371

Answers (2)

Julien Ch.
Julien Ch.

Reputation: 1261

By default Ajax request are executed asynchronously, so you have no guarantee what so ever which request will en and when. Since change should trigger before click and all the javascript is executed on a single you can either :

  • make your $.ajax call with the option { async : false }, but that will make your calls blocking

  • you keep track of what Ajax queries are running and you execute the remains ajax queries at the completion of the previous ajax query

Here is a possible solution keeping the asynchronous behaviour:

​Service=new function(){
  var onGoingAjax = null;
  var onComplete = null;

  this.change = function () {
    // Cancel previous call
    if (onGoingAjax) onGoingAjax.abort();
    // Run the new Ajax call
    onGoingAjax = $ajax( { /* options */ });
    onGoingAjax.done( function() {
      // mark the ajax call as finished
      onGoingAjax=null;
      // process the second call (if any)
      processComplete();
    });
  };

  this.click = function (){
    endFunc = function() { $ajax( { /* options */ }); };
    processComplete();
  };

  function processComplete()
  {
    // check if ajax still executing => the skip this call
    if (onGoingAjax != null) return;
    // check if a complete function is set => call it
    if (onComplete) onComplete();
    // reset the complete function
    onComplete = null;
  };
}()​;

$(document).ready(function(){
  $("input", form).change(Service.change);
  $("#validateAmt").click(Service.click); 
});

Upvotes: 1

jfriend00
jfriend00

Reputation: 707298

Don't rely on change events always firing before other things happen. Just always validate your data before sending to server (and always validate on the server too).

If validating is expensive (e.g. it takes an ajax call), then you can add an optimization to keep track of whether a specific value has already been validated or not, but that's just a performance optimization, not part of your core logic.

Upvotes: 0

Related Questions