Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are recursive AJAX calls a bad idea?

I have a simple function to pull in an array of templates:

function getTemplates(names, done, templates, index) {
    if (!index) index = 0;
    if (!templates) templates = {};
    if (index === names.length) return done(templates);
    $.ajax({
        url: '/templates/' + names[index] + '.min.html',
        success: function (data, status, xhr) {
            templates[names[index++]] = data;
                return getTemplates(names, done, templates, index);
        }
    });
}

It seems logical to me to just go from one to the next until they are all retrieved, then callback to the calling function. But I'm curious if doing so has any bad side effects. I haven't seen any so far, but I don't want to go to production with this without first getting some insight on any potential problems.


UPDATE: With the help of Google and BenjaminGruenbaum I've devised a solution:

function getTemplatesAsync(names, done) {
    var calls = [];
    var templates = {};
    names.forEach(function (name, index) {
        calls.push(
            $.ajax({
                url: '/templates/' + names[index] + '.min.html',
                success: function (data, status, xhr) {
                    templates[names[index++]] = data;
                }
            })
        );
    });
    $.when.apply($, calls).done(function () {
        // using "templates" here feels fragile for some reason.  Am I wrong?
        return done(templates);
    });
}

I'm using templates here because I need to be able to refer to each template by name, but somehow it feels fragile or unreliable. Does this look like a safe thing to do?

like image 516
Stephen Collins Avatar asked Apr 08 '14 14:04

Stephen Collins


1 Answers

Yes. Making multiple AJAX calls this way is a bad idea, but possibly not for the reason that you think.

This is going to cause all of your calls to be executed sequentially rather than making the calls in parallel and waiting for them to finish that way.

You'd be far better off using promises to make all of your calls and then waiting for all of them to finish before continuing. It would look something like:

var promises = [], templates = [], i;
for(i = 0; i < names.length; i++) {
    promises.push($.get('/templates/' + names[i] + '.min.html'));
}

$.when.apply($, promises).done(function(responses) {
   for(i = 0; i < responses.length; i++) {
       templates.push(responses[i][0]);
   }
});
like image 141
Justin Niessner Avatar answered Sep 30 '22 01:09

Justin Niessner