Troy
Troy

Reputation: 399

Synchronous Json calls from javascript

I'm working on a project where inside a loop I need to make multiple JSON calls. As soon as I exit that loop I need to work with the results of all the calls I made. I'm having a hard time understanding how to make these calls in such a way that my order of operation works out. My code to work with the results always executes before the calls to the service have completed. I created a jsfiddle to demonstrate and am including the code here.

http://jsfiddle.net/VEkrf/3/

    var sourceData = { "fooIndex": "foo",
        "barIndex": "bar"
    }
    var destinationData = {};
    for (var sourceIndex in sourceData) {
        $.getJSON('http://echo.jsontest.com/' + sourceIndex + '/' + sourceData[sourceIndex] + '?callback=?', null, function (result) {
            for (var resultIndex in result) {
                alert("Adding " + resultIndex + " : " + result[resultIndex]);
                destinationData[resultIndex] = result[resultIndex];
            }
        });
    }

    if (Object.keys(destinationData).length == 0) {
        alert("Destination not yet populated");
    }
    else {
        alert("Eureka!  You did it!");
    }

Upvotes: 2

Views: 1281

Answers (2)

gen_Eric
gen_Eric

Reputation: 227270

This looks like a job for jQuery Deferred Object, and my sidekick $.when!

Pass all the $.getJSON calls to $.when, and when they are all done, I'll will call a function with all the results.

Check this out:

var sourceData = {
    "fooIndex": "foo",
    "barIndex": "bar"
};
var destinationData = {};

// Array of AJAX calls
var AJAX = [];

for (var sourceIndex in sourceData) {
    AJAX.push($.getJSON('http://echo.jsontest.com/' + sourceIndex + '/' + sourceData[sourceIndex] + '?callback=?'));
}

// Apply is needed to pass each element as a parameter
$.when.apply($, AJAX).done(function(){
    // This function will be called when all the AJAX calls are done

    // The arguments of the functin are the responses from each request
    for(var i = 0, len = AJAX.length; i < len; i++){
        var result = arguments[i][0];
        //arguments: [resultObj, 'success', jqXHR]
        for (var resultIndex in result) {
            alert("Adding " + resultIndex + " : " + result[resultIndex]);
            destinationData[resultIndex] = result[resultIndex];
        }
    }

    alert("Eureka!  You did it!");
});

NOTE: Since this is asynchronous, destinationData won't be available until the callback is triggered. Put any code that uses that inside the .done() callback.

Upvotes: 5

Pow-Ian
Pow-Ian

Reputation: 3635

Since you are using jQuery already I suggest exploring the queue functions. You can queue the ajax calls and then in the success handlers call the de-queue or next function. this way they go in succession. The last item you add to the queue is your function that handles the returned data.

var sourceData = {
    "fooIndex": "foo",
    "barIndex": "bar"
};
var destinationData = {};

$(function () {
    console.debug('ready');
    for (var sourceIndex in sourceData) {
        console.debug('for Loop');
        $(document).queue('ajax', function (next) {
            $.getJSON('http://echo.jsontest.com/' + sourceIndex + '/' + sourceData[sourceIndex] + '?callback=?', null, function (result) {
                for (var resultIndex in result) {
                    alert("Adding " + resultIndex + " : " + result[resultIndex]);
                    destinationData[resultIndex] = result[resultIndex];
                    next();
                }
            });
        });
    }

    $(document).queue('ajax', function (next) {
        alert("Eureka!  You did it!");
    });
    $(document).dequeue('ajax');
});

I do this all the time for 'synchronus' ajax.

here is an example of what i am talking about

Upvotes: 3

Related Questions