I’ve tried to put this in generic terms to make it easier to understand. Please understand that it’s the concept, not the specific example that I’m trying to overcome.
OK, so I have a bit of JavaScript that makes a call to a server to get an object, let’s say an order. The order has properties including an array of order item IDs. I then want to loop through said IDs and get the order item records and return them in an array, like this:
function GetOrderItems(orderId){
var orderItemIDs = GetOrderItemIDs(orderId); // array of order item IDs
var orderItems = [];
$.each(orderItemIDs, function(){
var orderItem = GetOrderItem(this); // ignore this function's implementation
orderItems.push(orderItem);
});
return orderItems;
}
The issue is that there could be quite a few order items, but I have to get them from the server 1 at a time (don’t ask, this won’t change). So, I want to let them know (using a jQuery UI modal dialog) how many orders there are so they have an idea of how long it will take. So, I try to inject the line noted below:
function GetOrderItems(orderId){
var orderItemIDs = GetOrderItemIDs(orderId); // array of order item IDs
var orderItems = [];
$("#modalDiv").dialog({title: orderItemIDs.length + " order items to get."});
$.each(orderItemIDs, function(){
var orderItem = GetOrderItem(this); // ignore this function's implementation
orderItems.push(orderItem);
});
return orderItems;
}
The problem is that dialog shows, but only when everything is all complete. I learned from a previous question that you could use setTimeout to get the modal to show, but how do I return the array that I’m building?
function GetOrderItems(orderId){
var orderItemIDs = GetOrderItemIDs(orderId); // array of order item IDs
var orderItems = [];
$("#modalDiv").dialog({title: orderItemIDs.length + " order items to get."});
setTimeout(function(){
$.each(orderItemIDs, function(){
var orderItem = GetOrderItem(this); //ignore this function's implementation
orderItems.push(orderItem);
});
return orderItems;
},0);
}
I’ve also doing a second setTimeout function to show progress, but it goes straight to the last one and none of the functions run, like this:
function GetOrderItems(orderId){
var orderItemIDs = GetOrderItemIDs(orderId); // array of order item IDs
var orderItems = [];
$("#modalDiv").dialog({title: orderItemIDs.length + " order items to get."});
setTimeout(function(){
$.each(orderItemIDs, function(){
setTimeout(function(){
var orderItem = GetOrderItem(this); //ignore this function's implementation
orderItems.push(orderItem);
},500);
});
return orderItems;
},0);
}
Thanks in advance!
You’ll have to do it asynchronously. There’s no other way to get the UI to refresh. See this related question. That means your calling code will have to change from:
To:
Presumably, you’ve only been able to get away with this synchronous code by making your server requests synchronous, thus tying up the browser, etc. If you are going to take the plunge into asynchronocity, you might as well take advantage of all the potential benefits. For example, your modal could be updated to indicate how many orders remain to be downloaded:
Edit: To limit concurrent requests, don’t use
$.each(). Instead start just the number of concurrent requests that you want, and then initiate the rest of the requests in the request’s success handler: