2

I am currently trying to search a bit about how Javascript handles data race in parallel or asynchronous calls. As far as I'm concerned, the only way to make asynchronous stuff on my code is by AJAX calls (correct if I'm wrong!), but I suppose that if there is another way, it will be handled likewise.

So, as an example, suppose that I have this AJAX call:

jQuery.ajax({
    //stuff
    success: function (data) {
        //do some fancy things with some DOM elements
    },
    //possibly more stuff
});

Suppose now that outside that call I am running other things, and I end up doing something with the same DOM element that my success callback deals within my AJAX call (i.e. appending elements on a table at the same time that my success callback tries to do the same thing). On another words, my configuration ends in some sort of a data race.

How does Javascript deals with this? When my AJAX response comes back, will my current running function be preempted so that the AJAX call be executed? Is there something that guarantees me that what I'm doing with my DOM element (or a javascript variable) is some sort of an atomic operation? So in case I need to run a function that must be atomic, how can I tell that to the interpreter?

Also, is there some shielding on Javascript to prevent deadlocks? Say, if I run two parallel AJAX calls and each one depends on the finishing of the other.

  • If something depends on the result of an async operation, then everything has to become async, with nested callbacks, or using promises. – elclanrs Mar 19 '15 at 02:57
  • 1
    You may find this [How does JavaScript handle AJAX responses in the background?](http://stackoverflow.com/questions/7575589/how-does-javascript-handle-ajax-responses-in-the-background/7575649#7575649) useful to read. – jfriend00 Mar 19 '15 at 03:19

4 Answers4

1

JavaScript doesn't have any built in protection against this. As part of your code design, you need to make sure that you don't get in a situation where you don't know which of two colliding functions is going to execute first.

This takes some planning. You can either put one Ajax call in the callback of another, or you use events and properties to let other functions know if something is ready for processing, or whether some object is being used and so it shouldn't be touched, etc.

juacala
  • 2,155
  • 1
  • 21
  • 22
  • Well that answers better the question about deadlocks, but how do I guarantee that a given AJAX call won't touch my object using properties if Javascript seems not to be able to handle atomic functionalities? – Guilherme Caminha Mar 19 '15 at 03:05
  • For instance, that would be an atomic access to an object: var = 0; function(obj) { a = 1; //access obj a = 0; } But that's obviously not true as the calls for a = 0 and a = 1 are not atomic. – Guilherme Caminha Mar 19 '15 at 03:06
  • I'm not 100% sure I understand, but I think the answer to your question is that JavaScript is not atomic. If something fails, there is no built in methodology to undo partial calls. You have to do that using try catch, etc. – juacala Mar 19 '15 at 03:12
  • Ops, I see now that I messed up that "atomic access function", as it does not check the state of "var". Anyway, someone else posted a link that describes that my success function would be pushed into the event queue, so it will run after all events are finished. Therefore, there can't be a direct data race, I believe. – Guilherme Caminha Mar 19 '15 at 03:30
  • 1
    Right. As long as you are in your callback, that is the only javascript being run. There's only a single thread. When an asynchronous action completes, it adds on the callback to the stack. So if you have to asynchronous calls running simultaneously, you won't know which callback will make it in the stack first, but only one will run at a time. – juacala Mar 19 '15 at 03:48
1

So for the first question:

Suppose now that outside that call I am running other things, and I end up doing something with the same DOM element that my success callback deals within my AJAX call (i.e. appending elements on a table at the same time that my success callback tries to do the same thing). On another words, my configuration ends in some sort of a data race.

For this you would simple use jQuery's $.Deferred functionality. All $.ajax calls return, what jquery calls, a deferred object. Also known as a promise object. Also known as a future in other languages. This allows you to execute functionality after the request has finished.

var req = $.get(url, successFunc);
req.done(someOtherFunc);

For the second question:

Say, if I run two parallel AJAX calls and each one depends on the finishing of the other.

I think what you're looking for here is $.when, which allows you to run functionality only when a list of requests have resolved.

$.when([req1, req2, req3], function (res1, res2, res3) {});
Dustin Hayes
  • 236
  • 2
  • 3
  • I see, that's cool. But then if want to things like appending stuff to my table, I **will** have to wait for the AJAX call to return, in order to avoid data race? I can't see why a language would implement asynchronous calls if it can't handle data race without making things a little synchronous. In fact, I can't see the difference between doing `req.done(someOtherFunc);` and simply calling this someOtherFunc inside my success callback (supposing my AJAX call would be a successful one, of course) – Guilherme Caminha Mar 19 '15 at 03:14
  • I guess I would say: 1. You data should't live in the DOM. You should have your data (models, stores, collections etc.) live outside of the DOM. 2. You have to deal with this in any language, whether it's asynchronous (via callbacks or promises) or via threads. If you want to want to deal with the most current data you need to: – Dustin Hayes Mar 19 '15 at 21:39
  • Were you going to say anything else more? Since you left a ':' at the end of your last sentence. – Guilherme Caminha Mar 21 '15 at 01:59
1

Browser - by extension the javascript(where the page is opened) runs like a single threaded application which can do only 1 thing at a time.

Which means that at any point of time, browser can either run javascript/listen for events or run reflow/repait activities.

Since that is the case at any point of time the browser window can execute only 1 function that means when the ajax response comes back if there is a function that is running then the ajax callback will be added to the execution queue which will get executed when the current function is completed.

You can also achieve asynchronous operation by using setTimeout/setInterval even they would not guarantee that the callback will be executed exactly after 1000ms or whatever delay is given, they just says that it will get executed in the nearest slot that is available

Community
  • 1
  • 1
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • Are you sure that the ajax callback will run after the current function is completed? If I make nested function calls, like this: `a = function () { b = function() { c = function() { // ... }; c(); }; b(); }; a()` If I'm now running function c(), after it ends, the callback will run? Or will it wait until a() is complete? I'm asking you that because I want to know if Javascript would possibly end up preempting my program while I'm in the middle of something like an attribution or sum: `x = 5 + y` If that's not the case, then this function: – Guilherme Caminha Mar 19 '15 at 03:22
  • (exceeded max char count, continuing...) `var k = 0; function(obj) { if(k == 0) { k = 1; //access obj k = 0; return true; } else { return false; } };` would be considered for me as atomic in some sense, as it would work as a "trylock" on pthread.h (C). – Guilherme Caminha Mar 19 '15 at 03:25
  • @GuilhermeCaminha execution of a function will not get interrupted for the execution of another function... given there is no async calls in the first function – Arun P Johny Mar 19 '15 at 03:29
  • Yes, now I see that. Someone else posted this link: http://stackoverflow.com/questions/7575589/how-does-javascript-handle-ajax-responses-in-the-background/7575649#7575649 Your second link is also very interesting. Thanks. – Guilherme Caminha Mar 19 '15 at 03:37
1

Try utilizing Promise.race()

var request = function(url) {
  return new Promise(function(resolve, reject) {
    var res = $.ajax({
        url: url,
        type: "GET"
    });
    res.then(function success(data) {
      resolve(data)
    }, function error(jqxhr, textStatus, errorThrown) {
      reject([textStatus, errorThrown])
    })
  })  
};

var promises = Promise.race([
  request("https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js")
, request("https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js")
]);

promises.then(function(response) {
 console.log(response)
}, function(error) {
  console.log(error)
});
guest271314
  • 1
  • 15
  • 104
  • 177