user12175383
user12175383

Reputation: 37

async function resolve with Promise but returns undefined

I'm reading data from db with using await so I used Promise but the function seems to return nothing

async function read() {
  return new Promise((resolve, reject) => {
    const db = new DB();
  
    db
    .read()
    .then(result => {
      resolve(result);
    }).catch(() => {
      reject('db-error');
    });
  });
}

(async () => {
  const data = await read();

  console.log(data); // undefined
})();

How can I make read() return result?

Upvotes: 0

Views: 542

Answers (2)

dekarpaulvictor
dekarpaulvictor

Reputation: 131

The awesome guys who write the MDN Web Docs say that the result of await will be undefined if the promise that is being waited on is rejected: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#handling_rejected_promises

Check out the following scenario.

This is a simple function that returns a Promise:

function asyncFunc(waitTime) {
  return new Promise((resolve, reject) => {
   setTimeout(() => {
     // say we prefer people who do things in 3 seconds or less
     if (waitTime <= 3000) {
       resolve('Promise resolved! You\'re fast! :)');
     } else {
       reject('Promise rejected! You\'re slow! :(');
     }
   }, waitTime);
 });

}

Let's test the function using a method similar to yours:

async function testAsyncFunc(waitTime) {
  try {
    const result = await asyncFunc(waitTime);
    console.log(result);
  } catch(error) {
      console.error(error.message);
  }
}

testAsyncFunc(3000); // Returns `Promise resolved! You're fast! :)`, as expected

testAsyncFunc(3001); // Returns `undefined` instead of `Promise rejected! You're slow! :(` 

But since we want the actual rejection error of the asynchronous operation instead of undefined, the solution is to chain catch to the await statement to catch any rejection errors immediately you call the asynchronous function and then throw the error so it can be caught by any catch error handler you may want to use, like so:

async function testAsyncFunc(waitTime) {
  try {
    const result = await asyncFunc(waitTime)
      .catch(error => {
        // throw the rejection error so it can be handled by the catch block below
        throw new Error(error);
      });
    // if no errors
    console.log(result);
  } catch(error) {
      console.error(error.message);
  }
}

testAsyncFunc(3001); // Returns the expected result: `Promise rejected! You're slow! :(`

Upvotes: 0

Felix Kling
Felix Kling

Reputation: 816570

You are making it more complicated than it has to be. If you are already using an API that returns a promise then there is no need to use the promise constructor yourself.

And declaring a function as async is only necessary if you are using await in it to deal with promises.

So either do:

function read() {
  const db = new DB();
  return db
    .read()
    .catch(() => {
      return 'db-error';
    });
}

Or

async function read() {
  const db = new DB();
  try {
    return await db.read();
  } catch(error) {
    return 'db-error';
  }
}

If you are still not getting the value you want then you are not using the database API correctly and you have to read its documentation to figure out how to get back the right data.

Upvotes: 4

Related Questions