JavaScript synchronization options
Asked Answered
K

6

10

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?

Kantianism answered 9/5, 2009 at 10:4 Comment(0)
K
4

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
        }
    }
})();
Kantianism answered 11/5, 2009 at 14:2 Comment(1)
Thanks for this. I'm surprised how many said "it's single threaded so it's not a problem" which is totally incorrect in a world with asynchronous callbacks. You described the problem nicely and this is a perfectly effective approach for me.Leffler
R
8

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 );              
        };            
    });
Rafa answered 9/5, 2009 at 11:36 Comment(6)
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.Kantianism
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?Kantianism
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 withRafa
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.Kantianism
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 problemRafa
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.Kantianism
F
6

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).

Faucher answered 9/5, 2009 at 10:21 Comment(5)
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.Headship
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.Faucher
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.Kantianism
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.Faucher
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.Kantianism
K
4

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
        }
    }
})();
Kantianism answered 11/5, 2009 at 14:2 Comment(1)
Thanks for this. I'm surprised how many said "it's single threaded so it's not a problem" which is totally incorrect in a world with asynchronous callbacks. You described the problem nicely and this is a perfectly effective approach for me.Leffler
H
3

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.

Headship answered 9/5, 2009 at 10:36 Comment(3)
synchronous requests are bad because they prevent all other javascript event handlers from being executed.Faucher
I just answered his question, I didn't attempt to judge his need. Downvote that? heh.Headship
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.Headship
G
3

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.

Giarla answered 9/5, 2009 at 11:7 Comment(1)
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.Kantianism
O
1

I know it is way after but thought I would just give an improvement. Artem Barger worked out his own solution which uses setTimeout if the cached value is "updating" ... Instead just tag the function onto a linked queue against the cached value so you have an object which holds the actual cached data and the queue of functions to call with the cached data once the data is returned.

So, if it is "updating" just add your function to the queue which is linked against the item data and when the data returns...set the data and then iterate over the queue of functions (callbacks) and call them with the returned data.

if you wanted to get technical you could set a specific QOS timeout as you go through the queue, set a stop watch at the beginning of the iteration and if you reach a specific time then call a setTimeout to go back into the queue to continue the iteration...I hope you got that :) - It basically saves X amount of setTimout calls one only one is needed.

View Artem Bargers code above and you should get the gist of what I propose.

Oscaroscillate answered 19/9, 2017 at 17:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.