How to accumulate data from various AJAX calls? - javascript

Apart from making synchronous AJAX calls if you can and think it is appropriate, what is the best way to handle something like this?
var A = getDataFromServerWithAJAXCall(whatever);
var B = getDataFromServerWithAJAXCallThatDependsOnPreviousData(A);
var C = getMoreDataFromServerWithAJAXCall(whatever2);
processAllDataAndShowResult(A,B,C);
Provided that I can pass callbacks to those functions, I know I can use closures and lambdas to get the job done like this:
var A,B,C;
getDataFromServerWithAJAXCall(whatever, function(AJAXResult) {
A= AJAXResult;
getDataFromServerWithAJAXCallThatDependsOnPreviousData(A, function(AJAXResult2) {
B= AJAXResult2;
processAllDataAndShowResult(A,B,C);
});
});
getMoreDataFromServerWithAJAXCall(whatever2, function(AJAXResult) {
C= AJAXResult;
processAllDataAndShowResult(A,B,C);
});
function processAllDataAndShowResult(A,B,C) {
if(A && B && C) {
//Do stuff
}
}
But it doesn't feel right or clean enough to me. So is there a better way or at least a cleaner way to do the same thing or is it just that I'm not used to javascript functional programming?
By the way, I'm using jQuery (1.4.2) if that helps.
Thank you.

Yes, jQuery's Deferred Object is super handy.
Here's the example from the $.when() function documentation, illustrating a solution to your problem:
$.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.");
}
});
Cheers!

Make the callback function of each AJAX call to check/store results in a common local storage. And have another processing function that reads from this container, maybe at regular intervals or activated by each callback. This way you keep you functions clean and the focus on the Ajax call. This also keeps the accumulation scalable to n Ajax calls easy, and you dont have to modify existing code when adding a new call.

If you can use jQuery 1.5 you should be able to accomplish your needs via using the deferred object and $.when()
$.when(getDataFromServerWithAJAXCall("Call 1"), getMoreDataFromServerWithAJAXCall("Call 2")).done(function(a1, a2) {
var jqXHR = a1[2];
jqXHR.responseText;
getDataFromServerWithAJAXCallThatDependsOnPreviousData(jqXHR.responseText);
});
Simply put when the first two functions complete then it will execute the third function.
Example on jsfiddle

Use a so-called 'countdown latch'
Each of the functions have their own callback.
Have a variable called countdownlatch be upped each time a function is called and
count-down when each of the callbacks is reached (be sure to
countdown on async error as well.
Each of the callbacks separately checks to see if countdownlatch==0 if so call function
processAllDataAndShowResult
The beauty of javascript with these kind of async synchronizations is that implementing a countdownlatch is super-easy, because javascript is single-threaded, i.e: there's no way countdownlatch could get funky numbers because of racing conditions since these are non-existent (in this situation).
EDIT
Didn't see B depended on A, but the same principle applies:
var A,B,C;
var cdlatch = 2;
getDataFromServerWithAJAXCall(whatever, function(AJAXResult) {
A= AJAXResult;
getDataFromServerWithAJAXCallThatDependsOnPreviousData(A, function(AJAXResult2) {
B= AJAXResult2;
if(--cdlatch === 0){
processAllDataAndShowResult(A,B,C);
}
});
});
getMoreDataFromServerWithAJAXCall(whatever2, function(AJAXResult) {
C= AJAXResult;
if(--cdlatch === 0){
processAllDataAndShowResult(A,B,C);
}
});
function processAllDataAndShowResult(A,B,C) {
//Do stuff
}
I must admit it's not that clear as the general case I described earlier, oh well.

Related

ajax interface without then

I want to package a ajax call into an interface without then.
If i do like this, it will just return 'No ajax return';
var ajaxReturn = ajaxFunction();
function ajaxFunction(){
var text = 'No ajax return';
// get fileName using an ajax get
$.ajax();
return text;
}
If i do like this, it will be ugly for using then;
function ajaxFunction(){
var text = 'No ajax';
var dtd = $.Deferred();
$.ajax();
return dtd.promise();
}
$.when(ajaxFunction()).then();
I just want the interface to be simple and return the right thing, can i?
//return the right
var ajaxReturn = ajaxFunction();
function ajaxFunction(){
var text = 'No ajax';
var dtd = $.Deferred();
$.ajax();
return dtd.promise();
}
$.when(ajaxFunction()).then();
Whoa, what is all that? You do need .then but you don't need most of the surrounding stuff. $.ajax generates a promise for you. You don't need to make a promise object yourself. In fact, often the only reason you need to manually set up a Deferred/Promise directly is if you're using some library that sets up callbacks and doesn't use promises itself.
function ajaxFunction(){
return $.ajax();
}
ajaxFunction().then(function(data) { ... });
Now, let's say that you didn't actually want to return the JSON structure on the end of the ajax function; you want to take out just a number from inside of it, or tweak one value to make it an easier-to-use function for its callers. Easy enough:
function ajaxFunction(){
return $.ajax().then(function(data) {
return data[12].number;
}
}
ajaxFunction().then(function(number) { ... });
In direct answer to your question: No, what you asked for isn't possible. Whenever your JavaScript methods are running, the browser can't process other events like clicks and even basic scroll operations. So, any long-running operations (like contacting the server) do not return straight away, and instead offer a callback operation.
Well..., ajax is asynchronous so you either use .then() or use a callback logic... Doing synchronous ajax is not a option for me, so I won't even mention it.
The alternative to .then() would be something like this:
ajaxFunction(function(res){ // pass a function into it
// this will be called when the ajax is done
alert(res);
});
function ajaxFunction(callback){
// get fileName using an ajax get
$.ajax({
success: callback
});
}
But again, maybe you can use just a normal ajax callback pattern anyway
$.ajax({
...
success: function(res){
// use the res
}
});
Ajax is asynchronous. then is designed to make writing async operations look more similar to synchronous code and can actually be very elegant.
Additionally, $.ajax() returns a promise and is well suited to be written as follows:
function ajaxFunction(){
return $.ajax();
}
ajaxFunction().then(function(response){
// do whatever you want with the response
})
You simply can't write asynchronous code that way (ajaxResult = ajaxFunction()). The interpreter is going to keep trucking along line by line and ajaxResult will not be ready in time.
Read up on chaining $.Deferred's. It will really clean up your async code.

Wait For All synchronization pattern in Javascript

A JS control calls a data service and continues rendering itself without waiting for the result. Sometimes the service returns after the the controls is being fully rendered, sometimes - before. How do you implement WaitForAll in JS? I'm using jQuery.
Here's what I've done myself: (Utils.WaitForAll simply counts the number of hits once it's matched with the count it calls handle)
// before we started
var waiter = Utils.WaitFor({handle: function(e){ alert("got called"; }, count: 2});
the way it gets triggered:
// place one
waiter.Notify({one: {...}});
and then
// place two (can occur before one though)
waiter.Notify({two: {...}});
which triggers handle, handle has values tagged as one & two in its e. Waiter is an extra 'global' var, travelling down the stack, which i didn't quite like and it's a another new object after all... Any obvious problems with my approach?
You should take a look a promise interface of CommonJS (implemented by jQuery.Deferred) it provides progress callback which can be used in this case.
sample code:
var waiter = $.Deferred();
var len = 2;
waiter.done(function() {
alert("Hooray!!!");
});
waiter.progress(function() {
if(--len === 0) {
waiter.resolve();
}
});
// somewhere
$.ajax({
...
data: somedata,
success: function() {
waiter.notify();
}
});
// somewhere else
$.ajax({
...
data: someotherdata,
success: function() {
waiter.notify();
}
});
More about deferred:
jQuery Deferred API
Learn how to use Deferred here
How to use deferred objects in jQuery (from OP's answer to the same question)
I've found exactly wheat I need being jQuery Deferred, see the article:
http://richardneililagan.com/2011/05/using-deferred-objects-in-jquery-1-5/

Make AJAX "get" function synchronous / how to get the result?

I'm experiencing a problem of $.get function.
The url contains JSON
my code:
xyz = null
$.get('http://www.someurl.com/123=json', function(data) {
var xyz = data.positions[0].latitude;
});
alert(xyz);
//some more code using xyz variable
I know that xyz will alert a null result because the $.get is asynchronous.
So is there any way I can use the xyz outside this get function?
get is a shortcut. You can do the same, but synchronous, using:
var xyz = null
$.ajax({ url: 'http://www.someurl.com/123=json',
async: false,
dataType: 'json',
success: function(data) {
xyz = data.positions[0].latitude;
}
});
alert(xyz);
You'll have to declare the xyz variable before the ajax call, though.
The real answer is NO, but you can use this:
function useXYZ(){
alert(xyz);
}
xyz = null
$.get('http://www.someurl.com/123=json', function(data) {
xyz = data.positions[0].latitude;
useXYZ();
});
This is a common issue with Javascript. Javascript code must be written in continuation passing style. Its annoying but its something you can convert without thinking too much.
Basicaly, whenever we would have something like
var x = someSyncFunction(a, b, c);
//do something with x
console.log(x);
We can convert it into async code by making all the code after the function returns into a continuation function and turning x from a variable into a parameter of the continuation callback.
someAsyncFunction(a, b, c, function(x){
//do something with x;
console.log(x);
});
You have to watch out that its very easy to write confusing code. A good trick to keep in mind is taht you can make your own functions also receive callbacks. This allows them to be used by different function (just like normal sync helper functions that return a value can be used by different functions)
var getXyz = function(onResult){ //async functions that return do so via callbacks
//you can also another callback for errors (kind of analogous to throw)
$.get('http://www.someurl.com/123=json', function(data) {
var xyz = data.positions[0].latitude;
onResult(xyz); //instead of writing "return xyz", we pass x to the callback explicitely.
});
};
getXyz(function(xyz){ //this would look like "var xyz = getXyz();" if it were sync code instead.
console.log('got xyz');
});
The trick here is to change all return statements from the function into calls to the callback function. Think as if async function never returned and the only way to give a value back to someone is to pass that value to a callback.
You might ask why there isnt an easier way to do all of this. Well, there is not, unless you use another language instead of Javascript (or at least something that lets you write async code in synchronous style but automatically compiles down to regular Javascript)

Coordinating parallel execution in node.js

The event-driven programming model of node.js makes it somewhat tricky to coordinate the program flow.
Simple sequential execution gets turned into nested callbacks, which is easy enough (though a bit convoluted to write down).
But how about parallel execution? Say you have three tasks A,B,C that can run in parallel and when they are done, you want to send their results to task D.
With a fork/join model this would be
fork A
fork B
fork C
join A,B,C, run D
How do I write that in node.js ? Are there any best practices or cookbooks? Do I have to hand-roll a solution every time, or is there some library with helpers for this?
Nothing is truly parallel in node.js since it is single threaded. However, multiple events can be scheduled and run in a sequence you can't determine beforehand. And some things like database access are actually "parallel" in that the database queries themselves are run in separate threads but are re-integrated into the event stream when completed.
So, how do you schedule a callback on multiple event handlers? Well, this is one common technique used in animations in browser side javascript: use a variable to track the completion.
This sounds like a hack and it is, and it sounds potentially messy leaving a bunch of global variables around doing the tracking and in a lesser language it would be. But in javascript we can use closures:
function fork (async_calls, shared_callback) {
var counter = async_calls.length;
var callback = function () {
counter --;
if (counter == 0) {
shared_callback()
}
}
for (var i=0;i<async_calls.length;i++) {
async_calls[i](callback);
}
}
// usage:
fork([A,B,C],D);
In the example above we keep the code simple by assuming the async and callback functions require no arguments. You can of course modify the code to pass arguments to the async functions and have the callback function accumulate results and pass it to the shared_callback function.
Additional answer:
Actually, even as is, that fork() function can already pass arguments to the async functions using a closure:
fork([
function(callback){ A(1,2,callback) },
function(callback){ B(1,callback) },
function(callback){ C(1,2,callback) }
],D);
the only thing left to do is to accumulate the results from A,B,C and pass them on to D.
Even more additional answer:
I couldn't resist. Kept thinking about this during breakfast. Here's an implementation of fork() that accumulates results (usually passed as arguments to the callback function):
function fork (async_calls, shared_callback) {
var counter = async_calls.length;
var all_results = [];
function makeCallback (index) {
return function () {
counter --;
var results = [];
// we use the arguments object here because some callbacks
// in Node pass in multiple arguments as result.
for (var i=0;i<arguments.length;i++) {
results.push(arguments[i]);
}
all_results[index] = results;
if (counter == 0) {
shared_callback(all_results);
}
}
}
for (var i=0;i<async_calls.length;i++) {
async_calls[i](makeCallback(i));
}
}
That was easy enough. This makes fork() fairly general purpose and can be used to synchronize multiple non-homogeneous events.
Example usage in Node.js:
// Read 3 files in parallel and process them together:
function A (c){ fs.readFile('file1',c) };
function B (c){ fs.readFile('file2',c) };
function C (c){ fs.readFile('file3',c) };
function D (result) {
file1data = result[0][1];
file2data = result[1][1];
file3data = result[2][1];
// process the files together here
}
fork([A,B,C],D);
Update
This code was written before the existence of libraries like async.js or the various promise based libraries. I'd like to believe that async.js was inspired by this but I don't have any proof of it. Anyway.. if you're thinking of doing this today take a look at async.js or promises. Just consider the answer above a good explanation/illustration of how things like async.parallel work.
For completeness sake the following is how you'd do it with async.parallel:
var async = require('async');
async.parallel([A,B,C],D);
Note that async.parallel works exactly the same as the fork function we implemented above. The main difference is it passes an error as the first argument to D and the callback as the second argument as per node.js convention.
Using promises, we'd write it as follows:
// Assuming A, B & C return a promise instead of accepting a callback
Promise.all([A,B,C]).then(D);
I believe that now the "async" module provides this parallel functionality and is roughly the same as the fork function above.
The futures module has a submodule called join that I have liked to use:
Joins asynchronous calls together similar to how pthread_join works for threads.
The readme shows some good examples of using it freestyle or using the future submodule using the Promise pattern. Example from the docs:
var Join = require('join')
, join = Join()
, callbackA = join.add()
, callbackB = join.add()
, callbackC = join.add();
function abcComplete(aArgs, bArgs, cArgs) {
console.log(aArgs[1] + bArgs[1] + cArgs[1]);
}
setTimeout(function () {
callbackA(null, 'Hello');
}, 300);
setTimeout(function () {
callbackB(null, 'World');
}, 500);
setTimeout(function () {
callbackC(null, '!');
}, 400);
// this must be called after all
join.when(abcComplete);
A simple solution might be possible here: http://howtonode.org/control-flow-part-ii scroll to Parallel actions. Another way would be to have A,B, and C all share the same callback function, have that function have an global or at least out-of-the-function incrementor, if all three have called the callback then let it run D, ofcourse you will have to store the results of A,B, and C somewhere as well.
Another option could be the Step module for Node: https://github.com/creationix/step
You may want to try this tiny library: https://www.npmjs.com/package/parallel-io
In addition to popular promises and async-library, there is 3rd elegant way - using "wiring":
var l = new Wire();
funcA(l.branch('post'));
funcB(l.branch('comments'));
funcC(l.branch('links'));
l.success(function(results) {
// result will be object with results:
// { post: ..., comments: ..., links: ...}
});
https://github.com/garmoshka-mo/mo-wire

Pausing until a callback is called, in Javascript

I'm fairly new to the callback-style of programming in javascript.
Is there a way to force code to wait until a function call finishes via a callback?
Let me explain.
The following function takes a number and returns a result based upon it.
function get_expensive_thing(n) {
return fetch_from_disk(n);
}
So far, easy enough.
But what do I do when fetch_from_disk instead returns its result via a callback?
Like so:
function get_expensive_thing(n) {
fetch_from_disk(n, function(answer) {
return answer; // Does not work
});
}
The above doesn't work because the return is in the scope of the anonymous function,
rather than the get_expensive_thing function.
There are two possible "solutions", but both are inadequate.
One is to refactor get_expensive_thing to itself answer with a callback:
function get_expensive_thing(n, callback) {
fetch_from_disk(n, function(answer) {
callback(answer);
});
}
The other is to recode fetch_from_disk, but this is not an option.
How can we achieve the desired result
while keeping the desired behaviour of get_expensive_thing
-- i.e., wait until fetch_from_disk calls the callback, then return that answer?
Pretty much there's no "waiting" in browser Javascript. It's all about callbacks. Remember that your callbacks can be "closures", which means definitions of functions that "capture" local variables from the context in which they were created.
You'll be a happier person if you embrace this way of doing things.
add in that missing return :)
function get_expensive_thing(n) {
return fetch_from_disk(n, function(answer) {
return answer;
});
}

Categories