views:

3044

answers:

5

Hi, I was wondering whenever exists a solution to perform synchronization in JavaScript code. For example I have the following case: I'm trying to cache some response values from AJAX call, the problem is, that it's possible to perform simultaneously several calls, therefore it leads to race condition in the code. So I'm very curious to find solution for that? Any one has idea that to do?

+1  A: 

Javascript is inherently single-threaded, at least for the normal browser environment. There will never two simultaneous executions of scripts accessing the same document. (the new Javascript worker threads might be an exception here, but they're not meant to access documents at all, just to communicate by message passing).

fforw
Javascript may be single threaded but you can have race conditions, there's no guarantee of the order in which asynchronous requests are made, when they complete, etc. This is especially true with firefox-add ons and multiple windows.
apphacker
you obviously need to write code that can handle the problems you describe. This is not the same kind of synchronization you need in other languages to prevent threads from interfering with each other by reading incomplete results from memory or overwriting each others changes in between larger operations.There is only one active stream of javascript execution in the browser environment. all event handlers are called in a serialized fashion one after another.
fforw
Just try to write for instance one AJAX call, then in the handler call another AJAX request, and in the second handler access some global variable. And now make a several iterations of the first call. Are still sure there is a serialized access to that variable? Could you predict the order? And one more thing if I was able to write working code for problem I've described I would never ask here for help.
Artem Barger
The order is not predictable, but all responses are going to be handled serialized way, one after another. One response wins the race and the response handler gets called. if another response comes in while the first response handler is still running, the second response handler will have to wait until the first one exits.
fforw
Once responses have to race, there is an access violation in global variable access. In my case I clearly can see that handlers were called simultaneously and while first updating variable, second cannot see it and therefore perform unnecessary heavy computation again.
Artem Barger
+2  A: 

Yes you can make your xmlHttpRequests synchronous, in non-IE set the asynch option to false on the open method, in IE browsers do the same with the bAsync parameter.

Maybe you might want to chain your requests somehow. Create a que stack and send the requests as you make your way down the que.

apphacker
synchronous requests are bad because they prevent all other javascript event handlers from being executed.
fforw
I just answered his question, I didn't attempt to judge his need. Downvote that? heh.
apphacker
People may want synchronization for many different reasons, for example you want a request to be processed before handling any more user input. There are other reasons. Etc.
apphacker
+2  A: 

First, it's important to know that all current JS implementations are single-threaded, therefore we are not discussing race-conditions and synchronizing in the context it is usually used.

As a side note, browsers are now introducing worker threads which will allow concurrency in JS, but for now this is not the case.

Anyway, you still are facing issues with what data you are expecting to receive back form asynchronous calls and you have no guarantee as to the order you will receive things.

JS gives you a very nice solution to this with callbacks. For each asynchronous event you will be sending, attach a proper callback function to it, which will handle the event properly. Synchronization, in the way you mean it, should be happening there.

Yuval A
Ok, I my case I' trying to build the cache for some responses from server. There is a AJAX call, which does have it's own handler, but in the handler there is a call for function, which accessing the cache variable and if variable is set use it overwise make another heavy AJAX call. So if I'm using asynchronous call, I probably could miss the update of cache and perform unnecessary call twice, this behavior is unwilling, so I was thinking of the way I could synchronize the access for reading/writing of that variable.
Artem Barger
+2  A: 

I can offer a possible solution, but without seeing the code ... not completely sure what you are doing, but there is no reason why you couldn't do this.

Basic code in jQuery : (not tested and abbreviated ... but I have done things similar)

var needAllThese = {};

$(function(){

      $.ajax("POST","/somepage.aspx",function(data) {
          needAllThese.A = "VALUE";
      });

      $.ajax("POST","/somepage2.aspx",function(data) {
          needAllThese.B = "VALUE";
      });

      $.ajax("POST","/somepage3.aspx",function(data) {
          needAllThese.C = "VALUE";
      });

      startWatching();
});

function startWatching() {
   if (!haveEverythingNeeded()) {
       setTimeout(startWatching,100);
       return;
   }
   everythingIsLoaded();
}

function haveEverythingNeeded() {
    return needAllThese.A && needAllThese.B && needAllThese.C;
}

function everythingIsLoaded() {
   alert("Everything is loaded!");
}

EDIT: (re: your comment)

You're looking for callbacks, the same way jQuery would do it.

   var cache = {};

   function getSomeValue(key, callback) {
       if (cache[key]) callback( cache[key] );

       $.post( "url",  function(data) {
           setSomeValue(key,data);
           callback( cache[key] );
       }); 
   }

   function setSomeValue(key,val) {
        cache[key] = val;
   }

   $(function(){       
        // not sure you would need this, given the code above
        for ( var i = 0; i < some_length; ++i)  {
            $.post( "url", function(data){ 
                setSomeValue("somekey",data); 
            });
        }

        getSomeValue("somekey",function(val){            
             $("#element").txt( val );              
        };            
    });
Chad Grant
code looks like this:$(function(){for ( var i = 0; i < some_length; ++i)$.post( "url", function(data){ setUpSomeValue( data);});var setUpSomeValue = (function(){ var cache = {} return function( data){ if (!cache[data]) $.post(.....) //update cache with new data else return cache[data];}})();So whenever two similar data is returned I'm still doing the second AJAX call, because I'm unable to notify about cache update. So that's why I'm think about making some synchronization there.
Artem Barger
To be honest I'm not sure I understand how you last solution will help me in my problem. Do you mind to explain a little?
Artem Barger
It does exactly what you asked. Using callbacks ... and if you wrote the example code in your comment, you're using callbacks in your .$post call, it's the same concept ... you should have no problem understanding it unless you didn't write the code you're having trouble with
Chad Grant
So let say, some_length = 2 consequently it will produce two $.post() calls. And let say say both will return the same date. Now the second call takes a lot of time to response so the first call for setSomeValue will produce another $.post(), meanwhile the value is not updated, so the second call will be sure that there is no value in the cache and will call second time the unnecessary code. So I still don't see how your solution solves this case.
Artem Barger
I pointed out the unnecessary code. I would consider redesigning your app/data if you are having this many issues. I have not met a race condition like you talking about and I've been coding jQuery / JSON services every day for 2 years. Maybe you should get all the dates in one call .. who knows. Like I said, no code and I am just guessing at your problem
Chad Grant
I don't have that many issues, actually only one. I'm trying to optimize and perform as less calls as I could to server and trying to do the calls itself as lighter as it could be. Anyway your solution has same BUG/issue and it's really weird you don't see. The calls is asynchronous so they are independent, so then I call twice for setSomeValue with same key value, the first one will proceed $.post therefore will be waiting for result and cache will not be updated, so the second one, instead of waiting will perform second unnecessary code. Correct me if I'm wrong.
Artem Barger
A: 

I have found solution for my problem. I have to say it's not that perfect as I was looking for, but so far it works and I think about that more as temporarily work around.

$.post( "url1", function( data)
{
     // do some computation on data and then
     setSomeValue( data);
});

var setSomeValue = ( function()
{
    var cache = {};
    return function( data)
    {
        if ( cache[data] == "updating")
        {
             setTimeout( function(){ setSomeValue( data);}, 100);
             return;
        }
        if ( !cache[date])
        {
             cache[date] = updating;
             $.post( "url2", function( another_data)
             {
                  //make heavy computation on another_data
                  cache[data] = value;
                  // update the UI with value
             });
        }
        else
        {
             //update the UI using cached value
        }
    }
})();
Artem Barger