BayLife BayLife - 21 days ago 8
Node.js Question

Calling async promises inside async promise using .join()

I´m using node/ epxress, mysql and bluebird.

I´m currently doing an async database operation after the client request it. Inside the callback of the first database operation I have to perform some calculations first and afterwards doing two more database queries which are required to provide the client the correct result.

My Code is separated into a Controller class, which handles the get/ post request. In the middle a service class for business logic, which talks to a database class which queries in the database.

I´m currently able to do perform the first and second database request.

getVacation(departmentID) {

return departmentDatabase.getVacation(departmentID)
.then(result => [ result, result.map(entry => this.getDateRange(new Date(entry.dateFrom), new Date(entry.dateTo))) ])
.spread(function(result, dateRange){
var mergedDateRange = [].concat.apply([], dateRange);
var counts = {};
mergedDateRange.forEach(function(x) { counts[x] = (counts[x] || 0)+1; });

return [{"vacationRequest": result, "dateRange": dateRange, "countedDateRange": counts}];
})
.then( result => [result, departmentDatabase.countUser(departmentID)])
.spread(function (result, userOfDepartmentCount){
console.log(userOfDepartmentCount);
console.log(result);
//console.log(blocked);

return departmentID; //return just for not running into timeout
})
.catch(err => {
// ...do something with it...
// If you want to propagate it:
return Promise.reject(err);
// Or you can do:
// throw err;
});
}


But when trying to perform the third I´m running into trouble.
For a solution of this problem I read the Bluebird Doc´s, which pointed me to
.all()
or (even better)
.join()
. But trying to use either of them didn´t worked for me.

If I try it with
.join()
is always results in
join is not a function
, which I find confusing because I can use all other function. I also tried to require

var Promise = require("bluebird");
var join = Promise.join;


But not even this helped.


Currently I just require Bluebird as Promise in my database class.


So here now my entire service class.

'use strict';

var departmentDatabase = require('../database/department');
var moment = require('moment');

class DepartmentService {
constructor() {
}

getVacation(departmentID) {

return departmentDatabase.getVacation(departmentID)
.then(result => [ result, result.map(entry => this.getDateRange(new Date(entry.dateFrom), new Date(entry.dateTo))) ])
.spread(function(result, dateRange){
var mergedDateRange = [].concat.apply([], dateRange);
var counts = {};
mergedDateRange.forEach(function(x) { counts[x] = (counts[x] || 0)+1; });

return [{"vacationRequest": result, "dateRange": dateRange, "countedDateRange": counts}];
})
//THIS DOES NOT WORK
.join(result => [result, departmentDatabase.countUser(departmentID), departmentDatabase.blockedDaysOfResponsible(departmentID)])
.spread(function (result, userOfDepartmentCount, blocked){
console.log(userOfDepartmentCount);
console.log(result);
console.log(blocked);

return departmentID;
})
.catch(err => {
// ...do something with it...
// If you want to propagate it:
return Promise.reject(err);
// Or you can do:
// throw err;
});
}

getDateRange(startDate, stopDate) {
var dateArray = [];
var currentDate = moment(startDate);
while (currentDate <= stopDate) {
dateArray.push(moment(currentDate).format('YYYY-MM-DD'))
currentDate = moment(currentDate).add(1, 'days');
}

return dateArray;
}
}

module.exports = new DepartmentService();


Is someone able to give me an example how to do it right?

EDIT:

Here an example code I´m using inside my databaseCall, to return the db result and the promise

return Promise.using(dbConnection.getConnection(), function (conn) {
return conn.queryAsync(sql, [departmentID])
.then(function (result) {
return result;
})
.catch(function (err) {
return err;
});
});

Answer

Promise.join is nice, but it might not suit your situation the best. Promise.all will combine several promises like you have there into a single resolution:

.then(result => Promise.all([result, departmentDatabase.countUser(departmentID), departmentDatabase.blockedDaysOfResponsible(departmentID)])]‌​))

Then you could spread that result (an array) into a function call:

.spread(function(a, b, c) {
    console.log("Results", a, b, c);
});

Promise.all takes an array of Promises, waits for all of them to resolve (or reject), and then continues with the results in an ordered array into the subsequent .then (or other promise) clause.

Comments