Reputation: 301
I am fairly new to working with promises and now I got stuck. I read a few articles and SO posts, but I can't get my head around it.
I have a simple API that returns an array of people and some properties like firstname, lastname and d.o.b. I want to check for birthays within the next 10 days. Now I am stuck with the function returning a promise. I want the API to return an array with an array for people and an arry for nextBirthdays.
How do I resolve the promise?
( I know the part with calculating the dates is not the most elegant way to do it )
router.get('/', async(req, res) => {
try {
const contacts = await Contact.find()
// Returns promise, but want array
const nextBirthdays = getNextBirthdays(contacts)
var promise = Promise.resolve(nextBirthdays);
promise.then(function(val) {
console.log(val);
});
res.json({ contacts, nextBirthdays })
} catch (error) {
res.status(500).json({ message: error.message })
}
})
async function getNextBirthdays(contacts) {
contacts.forEach(async(contact) => {
let daysTillBirthday = await getDaysTillBirthday(contact.dob)
if (daysTillBirthday < 10 && daysTillBirthday > 0) {
console.log(`${contact.firstname}'s birthday is in ${daysTillBirthday} days`)
nextBirthdays.push({
firstname: contact.firstname,
days: daysTillBirthday
})
}
// Returns object with next birthdays
return nextBirthdays
})
}
async function getDaysTillBirthday(_birthday) {
const birthday = await birthdayDayOfYear(_birthday)
const today = await dayOfTheYear()
const days = birthday - today
return await days;
}
async function birthdayDayOfYear(date) {
const now = date;
const start = new Date(now.getFullYear(), 0, 0);
const diff = now - start;
const oneDay = 1000 * 60 * 60 * 24;
const day = Math.floor(diff / oneDay);
return await day
}
async function dayOfTheYear() {
const now = new Date();
const start = new Date(now.getFullYear(), 0, 0);
const diff = now - start;
const oneDay = 1000 * 60 * 60 * 24;
const day = Math.floor(diff / oneDay);
return await day
}
Upvotes: 0
Views: 6206
Reputation: 556
All of your utility functions for calling birthdays can be written as synchronous functions because you don't need to "wait" for a result, like you did for Contacts.find()
; they're just arithmetic operations that return immediately.
Although you could write these as asynchronous functions, it's unnecessary, so just remove all the async
modifiers from all of those functions and then all of the await
s in the return statements.
Then remove the async
in your forEach
loop which constructs the array of birthday results.
So the key thing to understand is that your birthday calculation can be done synchronously, so there is no need to resolve any promises at all. To understand how to resolve your promises, you could write your function as an asynchronous function like this, using your dayOfTheYear
as an example:
function dayOfTheYear() {
return new Promise((resolve) => {
const now = new Date();
const start = new Date(now.getFullYear(), 0, 0);
const diff = now - start;
const oneDay = 1000 * 60 * 60 * 24;
const day = Math.floor(diff / oneDay);
resolve(day); // this is you resolving the promise you return
});
}
If we were to use the above function, there would be two different ways to do it:
dayOfTheYear()
.then( (resolvedValue) => console.log(resolvedValue) )
The resolvedValue
is what was resolved in your function in the call to resolve(day)
.
Or instead of using the then
function to pass in a callback, you could instead use await
:
// assuming this code is in a function declared as async
const resolvedValue = await dayOfTheYear();
So from the above, you can see that the return
statement from an async function does the same thing as the resolve
call from a Promise callback.
One last thing: it's apparent from your code that you were getting confused by the declaration of functions as async. You declare a function async if you will be using await
to wait for the a Promise to resolve. If you don't declare async, you can't await anything. But you can only ever await Promises.
Under the hood, all these things are Promises and all Promises are just callbacks.
Hope this helped a bit.
Upvotes: 1
Reputation: 4452
Your code should look like this:
router.get('/', async (req, res) => {
try {
const contacts = await Contact.find()
const nextBirthdays = getNextBirthdays(contacts)
res.json({ contacts, nextBirthdays });
} catch (error) {
res.status(500).json({ message: error.message })
}
})
function getNextBirthdays(contacts) {
let nextBirthdays = [];
contacts.forEach(contact => {
let daysTillBirthday = getDaysTillBirthday(contact.dob)
if (daysTillBirthday < 10 && daysTillBirthday > 0) {
console.log(`${contact.firstname}'s birthday is in ${daysTillBirthday} days`)
nextBirthdays.push({
firstname: contact.firstname,
days: daysTillBirthday
})
}
})
// Returns object with next birthdays
return nextBirthdays
}
function getDaysTillBirthday(_birthday) {
const birthday = birthdayDayOfYear(_birthday);
const today = dayOfTheYear();
return birthday - today;
}
function birthdayDayOfYear(date) {
const now = date;
const start = new Date(now.getFullYear(), 0, 0);
const diff = now - start;
const oneDay = 1000 * 60 * 60 * 24;
return Math.floor(diff / oneDay);
}
function dayOfTheYear() {
const now = new Date();
const start = new Date(now.getFullYear(), 0, 0);
const diff = now - start;
const oneDay = 1000 * 60 * 60 * 24;
return Math.floor(diff / oneDay);
}
module.exports = router;
Upvotes: 1