0

I frequently need to load a function on a webpage after between two and five modest-sized data files have loaded. Let's say a maximum of 3MB of data split over a maximum of five files.

I try to optimize the load time by making all the AJAX calls at the same time and loading an initialize() function after they have all loaded, like so:

var data1, data2;
$(document).ajaxStop(function() {
  $(this).unbind("ajaxStop"); //prevent running again when other calls finish
  initialize();
});

$.ajax({
    url: url_to_data_1,
    success: function (d) {
       data1 = d;
    }
});

$.ajax({
    url: url_to_data_2,
    success: function (d) {
       data2 = d;
    }
});

function initialize() { /* do something with data1 and data2 */ }

But I'm tired of pasting this in every time, so I want a function like this:

function multi_Ajax(urls, callback) {
    var data = {};

    //call init() after both the list of prayers and the word concordance index load
    $(document).ajaxStop(function() {
      $(this).unbind("ajaxStop"); //prevent running again when other calls finish
      callback(data);
    });

    for (var c = 0; c < urls.length; c += 1) {
        //data files
        $.ajax({
          url: urls[c],
          dataType: "json",
          success: function (d) {
            data[urls[c]] = d; console.log("Loaded " + urls[c]);
          }
        });
    }    
}

This does not work, of course, since the ajax calls do not exist for ajaxStop to catch. But I do not understand how ajaxStop works well enough to get much further. Thank you!

Chris Wilson
  • 6,599
  • 8
  • 35
  • 71

1 Answers1

1

I'm not sure why your second attempt wouldn't work. According to the documentation, whenever an ajax request completes, jquery will check if there are any other requests that are still outstanding and fires ajaxStop if there are none. Calling $.ajax in a loop shouldn't be any different than hardcoding each call, as far as I can tell.

However, as Barmar suggested in the comments, $.when seems like a cleaner way to do what you want to do. Here's an example of how to pass an array (which you can populate in a loop) to $.when: Pass in an array of Deferreds to $.when()

Using $.when seems cleaner than $.ajaxStop because if someone later comes along and adds an unrelated ajax request somewhere before or after your loop, that would interfere with when ajaxStop triggers. $.when allows you to explicitly say which ajax requests you want to wait for.

EDIT: Here's a fiddle showing ajaxStop working for multiple calls issued in a loop: http://jsfiddle.net/zYk5W/

It looks like the reason this wasn't working for you has nothing to do with .ajax or .ajaxStop; instead it's a scope issue in your success callback. Your success callback closes over c, but this is the same c that the outer (loop) scope uses. By the time any of the success callbacks runs, the for loop has completed and c has been incremented to urls.length. Thus every time your success callback runs, urls[c] is undefined. See the fiddle I linked or JavaScript closure inside loops – simple practical example for an example of how to give each success callback its own c in a scope separate from the loop's c.

Community
  • 1
  • 1
Emily
  • 5,869
  • 1
  • 22
  • 15