JQuery ajax call chain with multiple dependencies

I don't quite understand magic deferred objects with jQuery. Suppose the following code:

function callWebService(uri, filter, callback)
{
  var data = {};

  if (filter && filter != '')
    data['$filter'] = filter;

  jQuery.ajax({
    url: '/_api/lists/' + uri + '/items',
    data: data,
    success: callback,
    dataType: 'json'
  });
}

function getInitialData() {
  callWebService("InitialData", "", function (data) {
    //do stuff with data
  });
}

function getGreenData() {
  callWebService("GreenData", "filter from InitialData", function (data) {
    //do stuff with data
  });
}

function getRedData() {
  callWebService("RedData", "filter from InitialData", function (data) {
    //do stuff with data
  });
}

function getFinalData() {
  callWebService("FinalData", "filter from RedData & GreenData", function (data) {
    //do stuff with data
  });
}

      

The order I want to do is, at the end of the day, I will call four webservices, whereas the calls are dependent on each other (one long chain):

  • Call getInitialData

  • Call getGreenData

    with dependencygetInitialData

  • Call getRedData

    with dependencygetInitialData

  • Call getFinalData

    with dependencies on getGreenData

    andgetRedData

As you can tell, 2 and 3 can happen at the same time. I think I can use jQuery.when()

(or resolve

?), I just don't know how to apply it here. I think I need to redesign the functions to always return an ajax object?

The pseude-code will look like this:

getInitialData().then(getGreenData, getRedData).then(getFinalData)

      

+2


source to share


2 answers


$. ajax returns jQuery promise. You can then call then

on that promise to complete the chain to the function. Ajax data

is passed as a promise parameter to any end callback function. This is because $ .ajax "promises returns Ajax data".

If you follow the same pattern for all of your functions, you can hook everything up the way you want. Without calling functions or adding anonymous callbacks, it just uses the resulting promises from each function call and concatenates them together.

Something like:

function CallWebService (uri, filter)
{
  var data = {};

  if (filter && filter != '')
    data['$filter'] = filter;

  return jQuery.ajax({
    url: '/_api/lists/' + uri + '/items',
    data: data,
    dataType: 'json'
  });
}

function getGreenData() {
  return CallWebService("GreenData", "filter from InitialData");
}

function getRedData() {
  return CallWebService("RedData", "filter from InitialData");
}

function GetInitialData() {
    return CallWebService("InitialData", "").then(GetGreenData);
}

// Fetch green data then red data sequentially
function GetFinalData () {
    return getGreenData().then(getRedData);
}

// Call the final one
GetFinalData().done(function(greendata, reddata){
     Alert("all done!");
});

      



To run promises in parallel, evaluate the features immediately and let the resulting promises combine with $.when

:

eg.

// Fetch green data and red data in parallel
function GetFinalData () {
    return $.when(getGreenData(), getRedData());
}

      

+4


source


Hopefully this gives a better idea of ​​how to transfer data from one call to another.

The first version callWebService()

differs in that:

  • it doesn't accept a callback
  • returns the jqXHR object returned $.ajax()

function callWebService (uri, filter) {
    var data = {};
    if (filter && filter != '') {
        data.$filter = filter;
    }
    return jQuery.ajax({
        url: '/_api/lists/' + uri + '/items',
        data: data,
        dataType: 'json'
    });
}

      

Now your four "get ..." functions differ in that:

  • functions take a parameter filter

  • functions return a promise
  • the callback now appears as a parameter passed to the chain .then()

    rather than passing it to callWebService()

    .
  • the callback does whatever is needed with the returned data, and importantly, returns it, thereby making the data available further down the promise chain, where it is called getInitialData()

    , getGreenData()

    etc.


function getInitialData (filter) {
    return callWebService("InitialData", filter).then(function (data) {
        //do stuff with initial data
        return data;
    });
}
function getGreenData (filter) {
    return callWebService("GreenData", filter).then(function (data) {
        //do stuff with green data
        return data;
    });
}
function getRedData (filter) {
    return callWebService("RedData", filter).then(function (data) {
        //do stuff with red data
        return data;
    });
}
function getFinalData (filter) {
    return callWebService("FinalData", filter).then(function (data) {
        //do stuff with final data
        return data;
    });
}

      

Finally, there is the main routine that controls sequencing and data flow.

function getAllSortsOfDependentData() {
    return getInitialData().then(function (initialData) {
        var filter1 = initialData...;//some property of initialData (this may be several lines of code)
        var filter2 = initialData...;//some other property of initialData (this may be several lines of code)
        var greenPromise = getGreenData(filter1);
        var redPromise = getRedData(filter2);
        return $.when(greenPromise, redPromise).then(function (greenData, redData) {
            var filter3 = greenData...;//some property of greenData (this may be several lines of code)
            var filter4 = redData...;//some property of redData (this may be several lines of code)
            return getFinalData(filter3, filter4).then(function(finalData) {
                //Now a summary object can be returned.
                //This is possible due to initialData/greenData/redData being accessible from closures formed by outer functions.
                return {
                    initialData: initialData,
                    greenData: greenData,
                    redData: redData,
                    finalData: finalData
                };
            });
        });
    });
}

      

getAllSortsOfDependentData()

can now be called like this, with the pivot data available in the chained callback .then()

:

getAllSortsOfDependentData().then(function(dataObject) {
    //Everything above is complete.
    //If required, all the fetched data is available here as properties of `dataObject`
    //dataObject.initialData
    //dataObject.greenData
    //dataObject.redData
    //dataObject.finalData
});

      

These are the basics. Various refinements are possible in almost every function.

0


source







All Articles