I\'m wondering how to make ajax calls in groups of n.
Here\'s my use case:
I have a table that displays usage data. You can drill into each row, and if eac
You can take a look at using jQuery.when, which allows you to execute callback functions when all requests have completed.
$.when($.ajax("request1"), $.ajax("request2"), $.ajax("request3"))
.done(function(data1, data2, data3){
// Do something with the data
});
Or
$.when($.ajax("request1"), $.ajax("request2"), $.ajax("request3"))
.then(successCallback, errorHandler);
See the following post for more information.
Also, I'm not sure that your apprehension towards using a plugin should be affected by the fact that you are in a work environment, especially if it simplifies your work. Hence allowing to be more productive. Granted you have to choose your plugins carefully, since quality and long term maintenance can be a issue.
The Recursive batching of calls works for me. But since I am getting 4K of XHR2 blobs and saving each one in the IndexedDB (PouchDB). I have threads for both the XHR2 and the IDB puts. So I had to be a bit more sophisticated:
for (var i in info.LayerInfo) {
var imageType = (info.LayerInfo[i].Class == "BASE") ? "jpg" : "png";
info.LayerInfo[i].SaveCount = 0;
getLayer(0, info, info.LayerInfo[i], info.LayerInfo[i].Path, imageType);
}
}
function getLayer(index, info, layer, base, imageType) {
if (layer.Files.length == 0) {
console.log("Thread done: " + index + " SaveCount: " + layer.SaveCount);
return;
}
var val = layer.Files.shift();
var path = base + "/" + val.id + "." + imageType;
$xhr.ajax({
url: path,
dataType: "blob",
success: function (data) {
console.log("fetched: ", layer.Type + "-" + val.id);
saveBlob(data, val.size, val.id, layer.Type, index, info, layer, base, imageType);
if (index < maxThreads - 1) {
getLayer(++index, info, layer, base, imageType);
} else {
return;
}
}
});
}
function saveBlob(blob, length, id, layerID, index, info, layer, base, imageType) {
if (blob.size != length) {
console.error("Blob Length found: ", blob.size, " expected: ", length);
}
var blobID = layerID + "-" + id;
var type = blob.type;
DB.putAttachment(blobID + "/pic", blob, type, function (err, response) {
if (err) {
console.error("Could store blob: error: " + err.error + " reason: " + err.reason + " status: " + err.status);
} else {
console.log("saved: ", response.id + " rev: " + response.rev);
layer.SaveCount++;
getLayer(index, info, layer, base, imageType);
}
});
}
Ajax calls using jQuery are typically asynchronous. So, if you have 50 rows, jQuery will asynchronously send all 50 requests--you don't get to control the sequence of processing when you get responses from the server.
You can use async: false
on the $.ajax
call such that only one request is sent to the server as you loop through your rows:
$.ajax({
url: location,
data: params,
async: false,
success: function(msg) { // do something}
});
The issue with this approach (async: false
) is that user may experience a "freeze" or unresponsive page.
Another way is to use recursion in your JavaScript so that the calls are still asynchronous but the ajax call still waits for the success event of each row like the following:
var maxRows = 50;
function myFunc(index) {
$.ajax({
url: location,
data: params,
async: true,
success: function(msg) {
if (index < maxRows) {
// do something
}
else {
return; //index equals maxRows--stop the recursion
}
index++;
myFunc(index); //call the function again
}
});
$(document).ready(function() {
myFunc(0);
});
}
I agree with eicto: make your own message manager if you can't integrate another one. Here's my crack at a tiny one:
var AjaxQueue = function(max) {
this.max = max;
this.requests = [];
this.current = 0;
}
AjaxQueue.prototype.ajax = function(opts) {
var queue = this;
opts.complete = function(jqXHR, textStatus) {
queue.current -= 1;
queue.send();
};
this.requests.push(opts);
this.send();
}
AjaxQueue.prototype.send = function(opts) {
while (this.current < this.max && this.requests.length > 0) {
$.ajax(this.requests.unshift());
this.current += 1;
}
}
I haven't tried using it yet, so there are bound to be bugs. Also it assumes you aren't using a complete
option. It just overrides it. If you are you could check for it and make sure the previous complete function(s) still get called.