Reputation: 3219
I have a function that looks up data in several different documents, add some of the date from each document to a object and returns the object with the combines data from the different documents. The only problem is that the object is returned before any of the transactions are completed. I have googled a lot, and the only solution i can find is on Stack Overflow, but from 2012.... There must be some "newer" better way to do it? Preferably without installing more npm stuff.
Here is my function
function getPreviousEventCard(event, callback) {
const card = {};
card.dateStart = event.dateStart;
card.dateEnd = event.dateEnd;
card.userID = event.userID;
card.adminID = event.adminID;
// 1st async call
Profile.getFullName(event.userID, (err, name) => {
if (err) return callback(err, null);
card.bsName = name.fullName;
});
// 2nd async call
Profile.getProfileByUserId(event.parentID, (err, profile) => {
if (err) return callback(err, null);
card.parentName = profile.fullName;
card.address = `${profile.address} ${profile.zip}`
});
// somehow wait until both(all) async calls are done and then:
return callback(null, card);
}
btw, 'Profile' is a mongoose schema, and the get methods are using the findOne() method.
I have tried to nest the functions and have the return callback as the most inner, but then it is never returned for some reason.
Upvotes: 1
Views: 230
Reputation: 1074335
If you're using NodeJS v8 or higher, I would promisify
those functions:
const getFullName = promisify(Profile.getFullName);
const getProfileByUserId = promisify(Profile.getProfileByUserId);
...and then use Promise.all
:
function getPreviousEventCard(event, callback) {
Promise.all([
// 1st async call
getFullName(event.userID),
// 2nd async call
getProfileByUserId(event.parentID)
])
.then(([name, profile]) => {
const card = {
dateStart: event.dateStart,
dateEnd: event.dateEnd,
userID: event.userID,
adminID: event.adminID,
bsName: name.fullName,
parentName: profile.fullName,
address: `${profile.address} ${profile.zip}`;
};
callback(null, card);
})
.catch(err => callback(err);
}
or better yet, make getPreviousEventCard
return a promise:
function getPreviousEventCard(event) {
return Promise.all([
// 1st async call
getFullName(event.userID),
// 2nd async call
getProfileByUserId(event.parentID)
])
.then(([name, profile]) => {
return {
dateStart: event.dateStart,
dateEnd: event.dateEnd,
userID: event.userID,
adminID: event.adminID,
bsName: name.fullName,
parentName: profile.fullName,
address: `${profile.address} ${profile.zip}`;
};
});
}
Preferably without installing more
npm
stuff
If you did want to install more npm
stuff, there's an npm
module that will promisify an entire API (rather than function by function) using a declarative description of the APIs functions: https://www.npmjs.com/package/promisify
Upvotes: 1