I have a function that gets's an object passed into it, with key and data that is an array. I have to call the API to get additional information, which in turn are added back into the object and the whole object is returned.
My first approach was incorrect because I was trying to pass the data out of the .then()
, but that was wrong practice.
function asignChecklistItems(taskArray) {
// get all the people's tasks passed in
return new Promise(function(resolve, reject) {
var promises = []
// Task Array: {"Person":[tasks,tasks,tasks]}
for (var person in taskArray) {
var individualTaskPerson = taskArray[person]
// get the person's tasks
for (var individualTask in individualTaskPerson) {
// here we get each individual task
var task = individualTaskPerson[individualTask]
// Check if the checklist is present, the .exists is a bool
if (task.checklist.exists === true) {
//Here we push the promise back into the promise array
// retrieve is the async function
promises.push( retrieveCheckListItems(task.checklist.checklistID)
.then(checklistItems => {
var complete = []
var incomplete = []
const items = checklistItems["checkItems"];
for (var each in items) {
const item = items[each]
if (item["state"] === "complete") {
complete.push(item["name"])
} else {
incomplete.push(item["name"])
}
}
task.checklist.completeItems.push(complete)
task.checklist.incompleteItems.push(incomplete)
return taskArray // used to be: resolve(taskArray) See **EDIT**
})
.catch(err => {
logError(err)
reject(err)
})
)
} else {
// There's no checklist
}
}
}
Promise.all(promises).then(function(x){
// Here when checked, all the items are pushed to the last person inside the array.
// Eg. {PersonA:[tasks],PersonB:[tasks],PersonC:[tasks]}
// All of the complete and incomplete items are added to Person C for some reason
resolve(taskArray)
})
})
}
I've tried many approaches, returning the entire promise, trying to return from within the promise (which didn't work because it's not allowed), and trying to run the async code earlier, and moving the for loops into the promise. None of them worked, this is the closest, where it returns it for PersonC.
This was mostly based on other SO questions such as this one, which showed how to use Promise.All
.
Is this the preoper way of calling a promise (async function) for each element of a for loop?
EDIT:
Another mistake that was in the code, is that if there is a promise insde a promise, such as the retrieveCheckListItems
inside of the asignCheckListItems
, it shouldn't resolve
itself, but it should return
the value. I updated the code to reflect that, based on the working production code.
Apparently another problem I was
You are executing task.checklist.completeItems.push(complete)
in the retrieveCheckListItems
.then
, which means the code is asynchronous.
At the same time, var task
is instead being assigned in a for...in
loop, which means that by the time your .then
is triggered, the for...in
iteration will be complete and task
will be the last assigned object.
Note that var
variables have a function scope, which basically means that your code is equivalent to:
function asignChecklistItems(taskArray) {
// get all the people's tasks passed in
return new Promise(function(resolve, reject) {
var promises = []
var individualTaskPerson;
var task;
...
Fix it by:
Either changing var task
to let task
(if you are using ES6). This then creates the variable within each for loop, rather than within the enclosing function.
or
By replacing
for (var individualTask in individualTaskPerson) {
// here we get each individual task
var task = individualTaskPerson[individualTask]
with
Object.keys(individualTaskPerson).forEach(function(individualTask) {
var task = individualTaskPerson[individualTask];
...
});
Do the same for the other for...in loops and variables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With