Join 2 'threads' in javascript

If I have an ajax call off fetching (with a callback) and then some other code running in the meantime. How can I have a third function that will be called when both of the first 2 are done. I'm sure it is easy with polling (setTimeout and then check some variables) but I'd rather a callback.

Is it possible?

Answers:

Answer

You could just give the same callback to both your AJAX call and your other code running in the meantime, use a variable to track their combined progress, then link them to a callback like below:

// Each time you start a call, increment this by one
var counter = 0;

var callback = function() {
    counter--;
    if (counter == 0) {
        // Execute code you wanted to do once both threads are finished.
    }
}
Answer

Daniel's solution is the proper one. I took it and added some extra code so you don't have to think too much ;)

function createNotifier() {
    var counter = 2;
    return function() {
        if (--counter == 0) {
            // do stuff
        }
    };
}

var notify = createNotifier();
var later = function() {
    var done = false;
    // do stuff and set done to true if you're done
    if (done) {
        notify();
    }
};

function doAjaxCall(notify) {
    var ajaxCallback = function() {
        // Respond to the AJAX callback here
        // Notify that the Ajax callback is done
        notify();
    };
    // Here you perform the AJAX call action
}

setInterval(later, 200);
doAjaxCall(notify);
Answer

The best approach to this is to take advantage of the fact that functions are first-order objects in JavaScript. Therefore you can assign them to variables and invoke them through the variable, changing the function that the variable refers to as needed.

For example:

function firstCallback() {
    // the first thing has happened
    // so when the next thing happens, we want to do stuff
    callback = secondCallback;
}

function secondCallback() {
    // do stuff now both things have happened
}

var callback = firstCallback;

If both your pieces of code now use the variable to call the function:

callback();

then whichever one executes first will call the firstCallback, which changes the variable to point to the secondCallback, and so that will be called by whichever executes second.

However your phrasing of the question implies that this may all be unnecessary, as it sounds like you are making an Ajax request and then continuing processing. As JavaScript interpreters are single-threaded, the Ajax callback will never be executed until the main body of code that made the request has finished executing anyway, even if that is long after the response has been received.

In case that isn't your situation, I've created a working example on my site; view the source to see the code (just before the </body> tag). It makes a request which is delayed by the server for a couple of seconds, then a request which receives an immediate response. The second request's response is handled by one function, and the first request's response is later handled by a different function, as the request that received a response first has changed the callback variable to refer to the second function.

Answer

You are talking about a thing called deferred in javascript as @Chris Conway mentioned above. Similarly jQuery also has Deferred since v1.5.

Check these Deferred.when() or deferred.done()

Don't forget to check jQuery doc.

But to give you some idea here is what I am copying from that site.

$.when($.ajax("/page1.php"), $.ajax("/page2.php")).done(function(a1,  a2){
    /* a1 and a2 are arguments resolved for the 
        page1 and page2 ajax requests, respectively */
   var jqXHR = a1[2]; /* arguments are [ "success", statusText, jqXHR ] */
   if ( /Whip It/.test(jqXHR.responseText) ) {
      alert("First page has 'Whip It' somewhere.");
   }
});

//Using deferred.then()

$.when($.ajax("/page1.php"), $.ajax("/page2.php"))
 .then(myFunc, myFailure);
Answer

Something like this (schematic):

registerThread() {
  counter++;
}

unregisterThread() {
  if (--counter == 0) fireEvent('some_user_event');
}

eventHandler_for_some_user_event() {
   do_stuff();
}
Answer

You can do this easily with Google's Closure library, specifically goog.async.Deferred:

// Deferred is a container for an incomplete computation.
var ajaxFinished = goog.async.Deferred();

// ajaxCall is the asynchronous function we're calling.
ajaxCall( //args...,
    function() {  // callback
      // Process the results... 
      ajaxFinished.callback();  // Signal completion 
    }
);

// Do other stuff...

// Wait for the callback completion before proceeding
goog.async.when(ajaxFinished, function() {
    // Do the rest of the stuff...
});

You can join multiple asynchronous computations using awaitDeferred, chainDeferred, or goog.async.DeferredList.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.