Moglash
Moglash

Reputation: 301

How do I return value from promise in javascript?

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

Answers (2)

Clinton Chau
Clinton Chau

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 awaits 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

Dheemanth Bhat
Dheemanth Bhat

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

Related Questions