2

It's not much I discovered Javascript Promise.
However I found out a behaviour I couldn't understand concerning the nesting of (new or returned) Promise inside Promises

That's the background (extPromiseX is a third-party function returning Promise):

Case 1:

function myAction(param) {
    return extPromise1(sql).then((result) => {
        [...]
        return extPromise2(sql2).then((result) => {
            [...]
            return extPromise3(sql3);
        })
   });
}

// Main Process
myAction(...)
.then(() => { 
    console.log('Process Terminated');
}).catch((error) => {
    console.error('Exit with error', error);
});

Now, as expected, I got from the console, in

1) extPromise1 completed
2) extPromise2 completed
3) extPromise3 completed
4) Process Terminated

Case 2:

function myAction(param) {
    return new Promise(function() {
        if (itsAllOkWithInputs) {
            // Some sync code here
            return extPromise1(sql).then((result) => {
                [...]
                return extPromise2(sql2).then((result) => {
                    [...]
                    return extPromise3(sql3);
                })
            })
        } else {
            throw 'Something went wrong';
        }
    });
}

// Main process
myAction(...)
.then(() => {
    console.log('Process Terminated');
}).catch((error) => {
    console.error('3) --> Exit with error', error);
})

In this second case extPromises are executed but the very first Promise remains pending (confirmed by debug). So the console shows:

1) extPromise1 completed
2) extPromise2 completed
3) extPromise3 completed

I empirically realized that I had to change myAction function as follow for the code to work:

function myAction(param) {
   return new Promise(function(resolve, reject) {
       if (itsAllOkWithInputs) {
           // Some sync code here
           let ep = extPromise1(sql).then(...);
           resolve(ep);
       } else {
           throw 'Something went wrong';
       }
   });
}

My question:
I thought returning a promise inside another parental one would make the parent resolving with the results of the child. This is the case inside the then code block applied to the external promises. Why this is not valid for the new Promise case?

Buzz
  • 1,102
  • 1
  • 9
  • 24
  • case 2: returning in a promise constructor makes no sense .. you need to resolve or reject in a promise constructor, however, since the code in the constructor already has a promise, then don't use the promise constructor anti-pattern – Jaromanda X Apr 08 '20 at 13:28
  • @JaromandaX: `myAction` has to return a `Promise`, but, before calling the external one, I have to manage checks upon inputs. This was the reason why I adopted a promise constructor. Any different solution? – Buzz Apr 08 '20 at 13:31
  • yes, promise chaining, you know ... `.then(....).then(....)` etc – Jaromanda X Apr 08 '20 at 13:34
  • Related: https://stackoverflow.com/questions/57504663/why-does-a-promise-return-an-object-promise-even-if-i-put-return-explicitly https://stackoverflow.com/questions/31324110/why-does-the-promise-constructor-require-a-function-that-calls-resolve-when-complete https://stackoverflow.com/questions/32780377/return-value-from-a-promise-constructor – Bergi Apr 08 '20 at 13:52

2 Answers2

2

Because .then is meant to chain promises. You can return a Promise from inside the then callback, and then itself will return a new Promise.

The Promise constructor is supposed to construct a Promise from an underlying callback. If you return a Promise from inside a Promise constructor, you are doing something wrong conceptually. And that's why it does not work.

 function myAction(param) {
   if (itsAllOkWithInputs) {
       return extPromise1(sql).then(...);           
   } else {
       return Promise.reject('Something went wrong');
   }
 }

 // OR
async function myAction(param) {
   if (itsAllOkWithInputs) {
       await extPromise1(sql);     
   } else {
       throw 'Something went wrong';
   }
 }
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
1
new Promise(function() {

You are not using neither resolve nor reject arguments (you actually even haven't declared them), so the promise will never get resolved or rejected. All other stuff is irrelevant.

If your function returns promise, you have to simply call it and return a result. If you don't know whether the function return promise or just a value, you can wrap it's call into Promise.resolve, but not in new Promise.

Qwertiy
  • 19,681
  • 15
  • 61
  • 128