skip to Main Content

For instance, I’m writing a Mongoose utility method, and I’m wanting to return a value after the async methods resolve. This is a highly simplified example.

const testConnect = () => {
    let msg;
    mongoose.connect(mongoServer.getUri())
        .then(() => {
            msg ="Connection success!";
        })
        .catch((err) => {
            msg = "Connection failure! Error: " + err;
        });
    return Promise.resolve(msg);
};

My test buildup utilizes this method in a matter like this.

beforeAll(() => {
    iMDT.testConnect()
        .then((result) => {
            console.log(result);
        })
        .catch((err) => {
            console.log(err);
        });
});

Is there a simpler, more organic way to return that value as a resolved promise – without using the prototype Promise? It feels kludgy to me.

3

Answers


  1. What you’re attempting to do won’t work because your asynchronous operation is non-blocking so you will do return Promise.resolve(msg); before there’s even a value in msg. It’s almost always a warning sign when you’re assigning higher scoped variables inside of a .then() or .catch() handler and then trying to use those variables at the top scope. That won’t work because of timing issues (attempting to use the variable before its value is set).

    Instead, you can just return the promise directly. The general advice is to use the promises you already have and not create new ones unnecessarily. Return the one you already have like this:

    const testConnect = () => {
        return mongoose.connect(mongoServer.getUri()).then(() => {
            // set the final resolved value
            return "Connection success!";
        }).catch((err) => {
            // set the final rejected reason object
            throw new Error("Connection failure! Error:"  + err.message, { cause: err });
        });
    };
    

    Note, how the failure option returns a rejected promise that contains a human readable message and also contains the original error object as the cause. This is the usual way to use promises, not to hide the rejection by returning a different resolved value. This allows the caller to more easily know if the operation succeeded or failed without having to compare to specific resolved values.

    And, this is also what your beforeAll() code block is expecting. It is expecting a rejected promise if the operation fails.

    Login or Signup to reply.
  2. The following example demonstrates an optimized code presented in a clear and concise manner. Please share some other approach if there is any even better answer, I’d like to gain some knowledge as well. Thank you.

    const testConnect = () => {
      return mongoose.connect(mongoServer.getUri())
        .then(() => "Connection success!")
        .catch((err) => "Connection failure! Error: " + err);
    };
    
    Login or Signup to reply.
  3. I’m a big fan of async/await. Allows for transparent readability.

    const testConnect = async () => {
        try {
            await mongoose.connect(mongoServer.getUri());
            return "Connection success!";
        } catch (err) {
            throw new Error("Connection failure! Error: " + err);
        }
    };
    
    beforeAll(async () => {
        try {
            const result = await iMDT.testConnect();
            console.log(result);
        } catch (err) {
            console.log(err);
        }
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search