You are correct due to the async calls your requests will possibly be done out of order. You can combat this by either using an IIFE or by moving your ajax call to a separate function and pass the index the page should be loaded to.

IIFE

for (var i = page; i < total; i++) { var full = query + "/" + i + ".html"; (function(idx){ $http.get(full). success(function (data) { pages[idx] = {image: $(data).find('img#image').attr('src')}; j++; //assuming j is a counter for knowing when pages are loaded if (j == total) { cb(pages); } }). error(function () { console.log("Error getting chapter"); }); })(i); }

Separate function call

function doAjax(url,pageArray,idx,cb){ $http.get(url). success(function (data) { pageArray[idx] = {image: $(data).find('img#image').attr('src')}; j++; //assuming j is a counter for knowing when pages are loaded if (j == total) { cb(pages); } }). error(function () { console.log("Error getting chapter"); }); } //.... for (var i = page; i < total; i++) { var full = query + "/" + i + ".html"; doAjax(full,pages,i,cb); }

Note since $http calls return a promise you can use $q.all to wait till all the pages are loaded to call your cb(pages) call instead of incrementing j and checking (I am assuming that is what your if statement for the cb(pages) is attempting to accomplish)