Reputation: 507
I have a Jquery function
group: function (text) {
var a1 = SPM.aChart();
var a2 = SPM.aSChart();
$.when(a1, a2).done(function () {//excecutes below function when all the charts are loaded.
SPM.EIEachGroup();
});
},
aChart and aSChart loads multiple charts and once everything is loaded i need to call EIEachGroup() function, the two functions are recursive ajax functions, currently EIEachGroup() function gets executed when the charts are not loaded, below is how i am returning promise from the ajax call.
aChart: function () {
var grpAttrId = 1;
var group = 'a';
var def = $.Deferred();
return $.ajax({
url: Url.getSegmentBreak,
type: 'GET',
data: { sgmntGrpAttrId: grpAttrId, selectedGroup: group },
dataType: 'json',
success: function (data) {
jQuery.each(data, function (index, item) {
$.ajax({
url: Url.GetScatterPlot,
type: 'GET',
data: { sgmntGrpAttrId: grpAttrId, selectedGroup: group, segmentBreak: item },
dataType: 'json',
success: function (data) {
SPM.GetSegmentScatterPlot(data,item);//function to plot chart
}
});
});
}
});
def.resolve();
return def.promise();
},
aSChart is also similar to above ajax, what changes has to be done to make EIEachGroup() called when both the functions are completely done.
--update - changed the function as mentioned, but still it would not wait till it finishes, below is the change i did
aMultiAxesChart: function () {
var grpAttrId = 1
var group = 'a'
var def = $.Deferred();
return $.ajax({
url: Url.getSegmentBreak,
type: 'GET',
async: false,
data: { sgmntGrpAttrId: grpAttrId, selectedGroup: group },
dataType: 'json'
}).done(function (data) {
var calls = jQuery.map(data, function (item, index) {
return $.ajax({
url: Url.GetHistMedTransData,
type: 'GET',
data: {
sgmntGrpAttrId: grpAttrId, selectedGroup: group, segmentBreak: item
},
dataType: 'json',
success: function (data) {
var seriesData = [];
var seriesData1 = [];
var seriesData2 = [];
var xCategories = [];
for (i = 0; i < data.length; i++) {
if (seriesData) {
var segName = data[i].MnthSmryStartDate;
if (xCategories.indexOf(segName) === -1) {
xCategories[xCategories.length] = segName;
}
seriesData1[i] = data[i].MedianTransactionAmt;
seriesData2[i] = data[i].MedianTransactionCnt;
}
}
seriesData = [
{
name: 'Amount',
type: 'column',
color: '#808080',
data: seriesData1,
tooltip: {
valueSuffix: ' mm'
}
}, {
name: 'Count',
type: 'line',
color: 'Red',
yAxis: 1,
data: seriesData2,
tooltip: {
valueSuffix: ' °C'
}
}
];
var divIndex = 1 + index;
var name = '#dvHistMed1' + divIndex;
SegmentProgressMeter.GetSegmentHistMedTransData(xCategories, seriesData, item, name);
}
});
});
return $.when.apply($, calls);
}).promise();
},
Upvotes: 0
Views: 109
Reputation: 507
var arr = [];
$.each(arr, function(i, v) {
var url = '/xml.php?id=' + v;
var xhr = $.ajax({
url: url,
type: 'GET',
dataType: 'xml',
success: function(xml) {
if ($(xml).find('Lists').attr('total') == 1) {
// some code here
}
},
complete: function() {
// some code here
}
});
arr.push(xhr);
})
$.when.apply($, arr).then(function(){
console.log('done')
})
Upvotes: 0
Reputation: 1074138
As Grundy pointed out, you're creating a Deferred
you never use. That's fine, you don't need it for anything — creating a new promise when you already have a promise to work with is an anti-pattern.
See code comments:
aChart: function () {
var grpAttrId = 1;
var group = 'a';
// Return the promise we get from the deferred we get from calling
// `done` on the first ajax call
return $.ajax({
url: Url.getSegmentBreak,
type: 'GET',
data: { sgmntGrpAttrId: grpAttrId, selectedGroup: group },
dataType: 'json'
}).done(function(data) {
// First call is complete, get promises for all the subordinate parallel calls
var calls = jQuery.map(data, function (item) { // Note that jQuery.map doesn't give you the index first
// Return the promise here; these will be collected into
// an array by jQuery.map
return $.ajax({
url: Url.GetScatterPlot,
type: 'GET',
data: { sgmntGrpAttrId: grpAttrId, selectedGroup: group, segmentBreak: item },
dataType: 'json',
success: function (data) {
SPM.GetSegmentScatterPlot(data,item);//function to plot chart
}
});
});
// Return a promise that waits on all of them (syntax is a bit strange, I know)
return $.when.apply($, calls);
}).promise(); // `done` returns Deferred, but we only want to return the Promise
},
The key to the above, and working with promises in general, is that when you call then
(or done
, which is a kind-of alias for then
on jQuery's Deferred
), the return value is a new promise (let's call it NewPromise). NewPromise will wait for the promise you called then
on to be settled, then call the callback you gave done
, and if that returns a promise, NewPromise waits on it; if the callback doesn't return a promise, NewPromise resolves itself using the return value as the resolution.
So:
return $.ajax(...).done(function() {
return somePromise;
});
...will give you a promise that will wait not only for the ajax call, but also for the promise returned by the done
callback.
This is a major part of the power of promises.
The reason for the weird $.when
syntax is that $.when
expects to receive individual promise arguments and wait for them all; it doesn't accept an array. Fortunately, JavaScript has Function#apply
that we can use to call a function with an array of arguments so that the function sees them as discrete arguments. So $.when.apply($, calls)
(the first argument to apply
is what to use as this
during the call). In ES2015, we'd be able to use $.when(...calls)
, but ES5 doesn't have the spread operator.
Upvotes: 1