Question

I'm trying to get my head around JQuery Deferred object. I'm working on a JS framework which loads a template and some JSON object and produces some HTML using those. The initial approach was loading them sequentially (pseudocode):

load_template(template_url, function (template_data) {
    load_json(json_url, function (json_data) {
       render(template_data, json_data);
    });
});

which is suboptimal, because json only starts loading after the template is loaded. I modified this to use Deferred object:

$.when(load_template, load_json).done(function (template_xhr, json_xhr) {
    render(template_xhr[0], json_xhr[0]);
});

So far so good. Now I have co-called "partials" which are some inline pieces of HTML which are built from a separate template and JSON data which are requested asynchronously and then inserted into the page. Currently I start loading them after the main template is rendered:

load_template(template_url, function (template_data) {
    load_json(json_url, function (json_data) {
       render(template_data, json_data);
       $.each(partials, function (idx, partial_url) {
           load_partial(partial_url, function (partial_data) {
               $("#some-element-id").html(partial_data);
           });
       }); 
    });
});

which, again, is sub-optimal, because I could start loading them concurrently right after the main template.

The problem with this, however, is that the partials can finish loading before the main template is loaded and rendered, so there's nowhere to insert them. Or they can finish later.

Sticking them into a single $.when() call is not good because I would like to display the page as soon as the main template and JSON data are ready, so the following would not work:

$.when(load_template, load_json, load_partial_template, load_partial_json, ...).done(function (template_xhr, json_xhr, ...) {
    render(template_xhr[0], json_xhr[0]);
    insert_partial(...);
});

So, the question is:

Is it possible, using Deferred object, to set up a series of ajax requests so they are divided into several groups:

  • all requests are initiated at the same time
  • when requests from "group 1" are finished a callback function is invoked
  • callbacks from "group 2"..."group n" are guaranteed not to be invoked before "group 1" callback, but they are still invoked eventually - either after the respective request completion or after the "group 1" callback, depending on what took longer.
Was it helpful?

Solution

Can you set up a collection of Deferreds for your partials, and a single main Deferred, and then only do something with the partial results after the main Deferred has finished?

var dfdPartials = [];
$.each(partials, function (idx, partial_url) {
    dfdPartials.push($.when(createDeferredForPartial(partial_url));
});

var dfdTemplate = $.when(load_template, load_json).done(function (template_xhr, json_xhr) {
    render(template_xhr[0], json_xhr[0]);
    $.each(dfdPartials, function (idx, dfd) {
        dfd.done(function (partial_data) {
            $("#some-element-id").html(partial_data);
        });
    });
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top