Home > Software design >  Promise rejection chaining from different js files
Promise rejection chaining from different js files

Time:08-01

I have a controller.js from where I call an async method in the service.js . Despite having a '.catch' block to deal with the Promise rejection, the program never goes there. It ALWAYS enters the '.then' block before any Promise is resolved.

Here's the code for the "controller.js" (the caller)

const Service = require('./service')

Service.serviceQueryDB("abc")
.then(result => /*  Immediately comes here, not waiting for the Promise to be resolved */
    console.log("I should have waited, but I'm already here. Resolved : ", result)) 
.catch(e => /*  Never enters this block. The error thrown by Service.serviceQueryDB is never caught
                   because the program runs immediately to the '.then' block */
    console.error("Rejected : ", e)) 

Here's the code for the "service.js" (the provider)

async function queryDB(str){
    return new Promise((_,rej) =>{
        setTimeout(()=>{
            console.log("Program is on DB now")
            rej("Query done!") /*I am 'rej'ecting the Promise*/
        },1000)
    })
}


async function serviceQueryDB(str){

        setTimeout(()=>{
            
            queryDB(str)
            .then( _ => {
                return new Promise((res)=>{
                    res("Query sucessfull")
                })
            })
            .catch(e => { /* the Promise rejection from the queryDB() is caught HERE, which is fine */
                return new Promise((_,rej) => {
                    console.error(e) /*  prints this 'Query done!', which is fine */
                    rej("Query unsuccessful") /*  however, this 'rej'ection is NOT caught in the controller, 
                                                      from where the method is called. Why? */
                })
            })
            
        }, 1000)
}

module.exports = {queryDB, serviceQueryDB}

So, the exception thrown should be caught on the controller.js and "Query unsuccessful" should be printed in the variable result here: console.log("I should have waited, but I'm already here. Resolved : ", result))

PS - if you copy/paste the code into two separate files and run node .\controller.js, you'll be able to reproduce the error

Thanks in advance

CodePudding user response:

async function serviceQueryDB(str){

    return new Promise((res,rej) => {
        
        setTimeout(()=>{
            
            queryDB(str)
            .then( _ => {
                    res("Query sucessfull")
                })
            .catch(e => {
                    rej("Query unsuccessful") 
                                                      
                })            
        }, 1000)
    })
}

CodePudding user response:


    return new Promise((res,rej) => { /* have to signal that the return will return a Promise - and that this return is the ONLY possibility of a return value*/
        
        setTimeout(()=>{
            
            queryDB(str)
            .then( _ => {
                    res("Query sucessfull")
                })
            .catch(e => { 
                    rej("Query unsuccessful") 
                })            
        }, 1000)
    })
}

CodePudding user response:

ok, so, I was fumbling around with the code, got a break and some coffee, and the answer is: I have to signal unequivocally that a Promise is being return by serviceQueryDB()

So if I change the code in that method on "service.js" to this:

async function serviceQueryDB(str){

    return new Promise((res,rej) => { /* have to signal that the return will return a Promise - and that this return is the ONLY possibility of a return value*/
        
        setTimeout(()=>{
            
            queryDB(str)
            .then( _ => {
                    res("Query sucessfull")
                })
            .catch(e => { 
                    rej("Query unsuccessful") 
                })            
        }, 1000)
    })
}

It works fine.

Prints:

Program is on DB now 
Rejected :  Query unsuccessful 

Everything else stays the same

CodePudding user response:

A more maintainable form of the OP's approach...

const wait = time => new Promise(resolve => setTimeout(resolve, time));

async function serviceQueryDB(str){
  return wait(1000)
  .then(() => {
    return queryDB(str)
  })
  .then(() => {
    return res("Query successful");
  });
}

When you later decide to remove the artificial waits, there's less editing...

async function serviceQueryDB(str){
  return queryDB(str)
  .then(() => {
    return res("Query successful");
  });
}
  • Related