I have this little program that calculates totals by multiplying a rate and some hours.
The problem I am having is that the function getTasks() always return an empty map. When I log the fields being entered in the map, they are not empty but they are entered after the function returns the map. So I am a bit confused why this is happening.
function getTask(taskId) {
return rp({
uri: `${url}/tasks/${taskId}`,
auth: {
user: 'user',
password,
sendImmediately: false
},
json: true
}).then((task) => {
return task;
});
}
function getTasks(entries) {
const taskIds = [];
entries.forEach((entry) => {
const taskId = entry.day_entry.task_id;
if (!taskIds.includes(taskId)) {
taskIds.push(taskId);
}
});
const taskRateMap = new Map();
taskIds.forEach((taskId) => {
return Promise.resolve(getTask(taskId)).then((res) => {
if (res.task.id === taskId) {
taskRateMap.set(taskId, res.task.default_hourly_rate);
console.log(taskRateMap);
}
});
});
return taskRateMap;
}
function calculateTasksTotals(id) {
return co(function* calculateTotalsGen() {
let total = 0;
const entries = yield getEntriesForProject(id);
const tasks = getTasks(entries);
entries.forEach((entry) => {
const rate = tasks.get(entry.day_entry.task_id);
total += rate * entry.day_entry.hours;
});
return total;
});
}
calculateTasksTotals(id)
There are multiple problems with your code:
First off, as soon as you have any asynchronous operation involved in a function, the result of that function is going to be asynchronous. You simply cannot return it synchronously. The async operation finishes sometime later. The function itself returns BEFORE the async operation finishes.
So, you return a promise from any function that uses an async operation and the caller uses that promise to know when things are done or to get the final result.
Your function
getTask()
is fine. It returns a promise. The.then()
inside that function is redundant and not needed sincetask
appears to already be the resolved value of the promise.Your function
getTasks()
is trying to synchronously returntaskRateMap
, but as you've seen in testing, none of the promises have resolved yet so there are no values intaskRateMap
yet. In my code version, I usePromise.all()
internally to know when all thegetTask()
operations are done and I return a promise who's resolved value is thetaskRateMap
object.The caller of
getTasks()
can then use that promise and a.then()
handler to get access to thetaskRateMap
object.Here's one way to implement
getTasks()
: