Reputation: 2446
I'm working on an angular app and am running into a problem. I'm fairly new to JS and very new to asynch programming so I'm guessing I'm missing something obvious.
The gist of the problem is that I have a for loop which builds an array. I then need to join that array as soon as the for loop has completed it's business. Normally this would be a no brainer but apparently in angular the for loop executes asynchronously. I need to force my array join to happen after the for loop exits.
if(!data.results[i].is_deleted) {
var objectsOnCurrentPermission = new Array();
if(data.results[i].objects) {
for(var j = 0; j < data.results[i].objects.length; j++) {
var currentObjectId = data.results[i].objects[j].object_id;
var currentObjectName;
var objectData = Object.get({id: currentObjectId}, function(objectData) {
objectsOnCurrentPermission.push(objectData.name);
console.log('in loop in get fn');
console.log(objectsOnCurrentPermission);
});
}
console.log('after loop');
console.log(objectsOnCurrentPermission);
var listOfObjectsOnCurrentPermission = objectsOnCurrentPermission.join(', ');
console.log('str after assignment');
console.log(listOfObjectsOnCurrentPermission);
data.results[i]['objects_list'] = listOfObjectsOnCurrentPermission;
}
To my surprise, when I inspect the output I see (I added '<'s for readability)
after loop permissions.js:246
>Array[1]
permissions.js:247
str after assignment permissions.js:249
permissions.js:250
in loop in fn permissions.js:242
>Array[1]
You can see that the after loop output executes first. From what I can tell, the first time it outputs Array[1] the array isn't actually populated - chrome just fills it in after the fact. The the blank line after the line that says "str after assignment" is where I try to output of the join which clearly didn't work. Then finally the code in the loop executes. As I mentioned I need to make sure that array join happens after the for loop has finished populating the array.
Upvotes: 0
Views: 538
Reputation: 707606
Based on your console.log()
output, it appears that the Object.get()
function must be asynchronous which means that calling it just starts it's execution and it finishes some time later. Presumably, when it does finish, it calls the callback function that you passed it.
So, to finish processing the end result, you will need to trigger your final code when the last Object.get()
call has completed - when all Object.get()
completion callbacks have been called. A simple counter that keeps track of how many there are remaining is one simple way of doing it.
Here's the basic idea for how you'd keep track of when all .get()
methods have completed and then trigger your final code:
if(!data.results[i].is_deleted) {
var objectsOnCurrentPermission = [];
if(data.results[i].objects) {
// initialize counter so we know when all async functions are done
var numRemaining = data.results[i].objects.length;
for(var j = 0; j < data.results[i].objects.length; j++) {
var currentObjectId = data.results[i].objects[j].object_id;
var currentObjectName;
var objectData = Object.get({id: currentObjectId}, function(objectData) {
objectsOnCurrentPermission.push(objectData.name);
console.log('get complete fn called');
console.log(objectsOnCurrentPermission);
--numRemaining;
if (numRemaining === 0) {
console.log('all get() functions done');
console.log(objectsOnCurrentPermission);
var listOfObjectsOnCurrentPermission = objectsOnCurrentPermission.join(', ');
console.log('str after assignment');
console.log(listOfObjectsOnCurrentPermission);
data.results[i]['objects_list'] = listOfObjectsOnCurrentPermission;
}
});
}
}
Upvotes: 3
Reputation: 2446
I ended up using caolan's async library to manage my sync/async code needs. Specifically async.parallel allowed me to build the intermediate arrays and ensure they are complete before moving on. https://github.com/caolan/async
Upvotes: 0