1

I am using promises to avoid the nesting structure created by callbacks.

However in this code I still have some nesting. Is there something I am doing wrong or is this un-avoidable in this case?

In this case I want to check and see if a profile exists and if it does not I want to create it.

  DB.getProfile(id_google).then((resGet) => {
    if(!resGet[0]){
      console.log('PROFILE - NOT FOUND - MUST CREATE');

      DB.createProfile(id_google, email, name, pic_url).then((resCreate)=>{
        console.log('PROFILE CREATED');
      }).catch((error) => {
        console.log('ERROR - createProfile() Failed: ', error);
      });

    } else {
      console.log('PROFILE FOUND LOCALLY');
      console.log(resGet[0]);
      return done(null, resGet[0])
    }
  }).catch((error) => {
      console.log('ERROR - getOrCreateProfile() Failed: ', error);
  });
};
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Are you ok with using async/await instead of promises in your application? – boysimple dimple Dec 21 '17 at 04:31
  • Yes, [nesting is pretty much unavoidable](https://stackoverflow.com/a/21578854/1048572) for conditional statements. – Bergi Dec 21 '17 at 04:40
  • You really should `return` from all your functions (to make a promise) instead of calling that `done` callback. That way, you wouldn't forget to call it (when an profile is created). – Bergi Dec 21 '17 at 04:44
  • 2
    @boysimpledimple async/await is not used "instead" of promises. It is used *with* promises, instead of `then` callbacks. – Bergi Dec 21 '17 at 04:45
  • @Bergi Yeah that's true. Async/Await is a syntactical wrapper for promises that makes regular control structures easier to use. – boysimple dimple Dec 21 '17 at 04:48
  • you need to get `id_google, email, name, pic_url` from `resGet `? – admcfajn Dec 21 '17 at 04:53
  • 1
    If you think that then I suggest you read [this](https://stackoverflow.com/questions/47664598/async-function-not-returning-value-but-console-log-does-how-to-do/47678417#47678417). It explains why callback/promises are used and how to use them. Your function resolves in undefined in case `resGet[0]` being falsy and when getProfile rejects. – HMR Dec 21 '17 at 05:02
  • @mikejacques It avoided nesting an inner `then` by simply dropping the `console.log('PROFILE CREATED')` – Bergi Dec 21 '17 at 22:43

2 Answers2

4

You can return and chain using multiple then

DB.getProfile(id_google)
    .then((resGet) => {
        if (!resGot[0]) {
            return DB.createProfile(id_google, email, name, pic_url);
        }
        return resGot[0];
    })
    .then((res) => {
        callback(null, res)
    })
    .catch((error) => {
        console.log('ERROR - getOrCreateProfile() Failed: ', error);
    });

If resGot[0] exist, then it is returned, and in the second then the variable res is that value. If it does not, then the promise of createProfile is returned and the value of res is whatever that function returns

Kousha
  • 32,871
  • 51
  • 172
  • 296
0

Sometimes it helps to boil your code down to the essentials:

getProfile
  if not found, 
    createProfile
       return profile
  else
    done profile

Presumably, you want to get createProfile outside in the same chain as the rest of the promise.

I changed the structure to:

getProfile
  if found, return profile 
  createProfile
    return profile
then
  done(profile)

It isn't really possible to have just one degree of nesting in this case. But you can reduce some level of nesting.

DB.getProfile(id_google)
.then((resGet) => {
    if(resGet[0]) {
      console.log('PROFILE FOUND LOCALLY');
      return resGet[0];
    }
    console.log('PROFILE - NOT FOUND - MUST CREATE');
    return DB.createProfile(id_google, email, name, pic_url)
    .then((resCreate)=>{
      console.log('PROFILE CREATED');
      return resCreate[0]; //Assuming resCreate looks like resGet
    })
  }
})
.then(profile=> {
    //The done function which belongs to passport is called once here.
    console.log(profile);
    return done(null, resGet[0])
})
.catch((error) => {
    console.log('ERROR - getOrCreateProfile() Failed: ', error);
});