Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding a Javascript race condition

My users are presented a basically a stripped down version of a spreadsheet. There are textboxes in each row in the grid. When they change a value in a textbox, I'm performing validation on their input, updating the collection that's driving the grid, and redrawing the subtotals on the page. This is all handled by the OnChange event of each textbox.

When they click the Save button, I'm using the button's OnClick event to perform some final validation on the amounts, and then send their entire input to a web service, saving it.

At least, that's what happens if they tab through the form to the Submit button.

The problem is, if they enter a value, then immediately click the save button, SaveForm() starts executing before UserInputChanged() completes -- a race condition. My code does not use setTimeout, but I'm using it to simulate the sluggish UserInputChanged validation code:

 <script>   var amount = null;   var currentControl = null;    function UserInputChanged(control) {       currentControl = control;       // use setTimeout to simulate slow validation code       setTimeout(ValidateAmount, 100);   }    function SaveForm() {       // call web service to save value       document.getElementById("SavedAmount").innerHTML = amount;   }    function ValidateAmount() {       // various validationey functions here       amount = currentControl.value; // save value to collection       document.getElementById("Subtotal").innerHTML = amount;   } </script>  Amount:   <input type="text" onchange="UserInputChanged(this)"> Subtotal: <span id="Subtotal"></span> <button onclick="SaveForm()">Save</button> Saved amount: <span id="SavedAmount"></span> 

I don't think I can speed up the validation code -- it's pretty lightweight, but apparently, slow enough that code tries to call the web service before the validation is complete.

On my machine, ~95ms is the magic number between whether the validation code executes before the save code begins. This may be higher or lower depending on the users' computer speed.

Does anyone have any ideas how to handle this condition? A coworker suggested using a semaphore while the validation code is running and a busy loop in the save code to wait until the semaphore unlocks - but I'd like to avoid using any sort of busy loop in my code.

like image 676
Jeremy Frey Avatar asked Dec 03 '08 17:12

Jeremy Frey


People also ask

How can a race condition be avoided?

Race conditions can be avoided by proper thread synchronization in critical sections. Thread synchronization can be achieved using a synchronized block of Java code. Thread synchronization can also be achieved using other synchronization constructs like locks or atomic variables like java.

How do you avoid race condition in node JS?

If you put all your programm in a main loop checking for new request queue, and then nest a loop checking for new data in the request, there will be no race condition anymore.

Can you have a race condition in Javascript?

Yes, we can have race conditions in Node. js!

What can we use to avoid race conditions in a multithreaded environment?

Another solution to avoid race condition is mutual exclusion. In mutual exclusion, if a thread is using a shared variable or thread, another thread will exclude itself from doing the same thing.


2 Answers

Use the semaphore (let's call it StillNeedsValidating). if the SaveForm function sees the StillNeedsValidating semaphore is up, have it activate a second semaphore of its own (which I'll call FormNeedsSaving here) and return. When the validation function finishes, if the FormNeedsSaving semaphore is up, it calls the SaveForm function on its own.

In jankcode;

function UserInputChanged(control) {     StillNeedsValidating = true;     // do validation     StillNeedsValidating = false;     if (FormNeedsSaving) saveForm();  }  function SaveForm() {     if (StillNeedsValidating) { FormNeedsSaving=true; return; }     // call web service to save value     FormNeedsSaving = false; } 
like image 124
zaratustra Avatar answered Sep 18 '22 01:09

zaratustra


Disable the save button during validation. Set it to disabled as the first thing validation does, and re-enable it as it finishes.

e.g.

function UserInputChanged(control) {     // --> disable button here --<      currentControl = control;     // use setTimeout to simulate slow validation code (production code does not use setTimeout)     setTimeout("ValidateAmount()", 100);  } 

and

function ValidateAmount() {     // various validationey functions here     amount = currentControl.value; // save value to collection     document.getElementById("Subtotal").innerHTML = amount; // update subtotals     // --> enable button here if validation passes --< } 

You'll have to adjust when you remove the setTimeout and make the validation one function, but unless your users have superhuman reflexes, you should be good to go.

like image 23
Andrew Rollings Avatar answered Sep 19 '22 01:09

Andrew Rollings