I would like to write a function getUser()
that returns a Promise where upon resolve
it delivers the user object and upon reject
it delivers the error. I'm using axios to make the request.
Here's what I currently have.
async function getUser() {
try {
const userResponse = await axios({
method: 'post',
url: "some_url",
data: "some string data",
headers: {
'content-type': 'application/x-www-form-urlencoded'
}
});
if (userResponse.data.status === 'success') {
// resolve(validateResponse.data);
} else {
// reject(validateResponse.data);
}
} catch (error) {
// reject(validateResponse.data);
}
}
I would like to wrap the entire try...catch
block inside a Promise
constructor, but the Promise constructor is new Promise((resolve, reject) => {...})
and not new Promise(async (resolve, reject) => {...})
. I know I can do the latter but it's an anti-pattern .
The Promise
approach doesn't necessarily work either because when I use the Promise
returned by getUser()
and .catch()
any errors, I won't know if the error came from the response from the server (the status was not 'success'
) or if the request itself failed.
What is the safest way to get around this problem? I know there is a brute force solution of just mimicking the Promise
API without actually using it, or declaring an async
Promise, but I feel like I'm encountering an anti-pattern every time.
Thanks for any suggestions.
I'll answer this conceptually.
When you call an async function, it immediately returns a promise to the code-scope that called that function.
Inside of an async function, you don't need to use resolve
and reject
. Instead you can just use return
and throw
. What ever you return
is what the promise will resolve to. If you throw
, that's what the promise will "reject" to. Try something like this:
async function getUser() {
try {
const userResponse = await axios({
method: 'post',
url: "some_url",
data: "some string data",
headers: {
'content-type': 'application/x-www-form-urlencoded'
}
});
if (userResponse.data.status === 'success') {
return validateResponse.data;
} else {
throw new Error(validateResponse.data);
}
} catch (error) {
throw error;
}
}
After async/await came out, I stopped liking the then
syntax when dealing with promises. To avoid then
, call getUser
from the body of an async function. If you're not calling getUser
from the body of an async function, you won't be able to await
what it resolves to; you'll have to use then
instead. Or, you can wrap that calling code in an immediately invoked async function just so you can indeed uses await
. Here's a rough example of how my code (that calls getUser
) might look:
(async function()
{
let user = await getUser();
if(!user)
{
console.error(`Access Denied`);
return;
}
// Rest of your code that should only run when you have a user goes here.
})();
The only reason I'm wrapping the code above in an immediately invoked async function, is so I can use await
instead of then
to resolve that promise.
Functions marked with async
are meant to be written using promise .then()
callback style. That is, in order to resolve a value you use the return
keyword and in order to reject a value you use the throw
keyword. Thus your function should be written as follows:
async function getUser() {
try {
const userResponse = await axios({
method: 'post',
url: "some_url",
data: "some string data",
headers: {
'content-type': 'application/x-www-form-urlencoded'
}
});
if (userResponse.data.status === 'success') {
return validateResponse.data;
} else {
throw new Error(validateResponse.data);
// Alternately you can also just:
// throw validateResponse.data
}
} catch (error) {
throw new Error(validateResponse.data);
}
}
The Promise approach doesn't necessarily work either because when I use the Promise returned by getUser() and .catch() any errors, I won't know if the error came from the response from the server (the status was not 'success') or if the request itself failed.
I would look at rejecting the outer promise inside getUser
in one of two examinable ways - and then call getUser
using a promise topology that splits good data into a processing stream (chain of promises), and errors into another for differentiation. For example:
Create a data wrapper constructor called, say, GetUserData:
const GetUserData = function( data) { this.data = data; }
This may benefit from having another parameter for getUser
argument values.
Remove the try {
and catch() {}
clauses. Let axios errors throw and reject the getUser
promise.
Have getUser
return the result of "success" or throw a GetUserData
object:
if (userResponse.data.status === 'success') { return userResponse.data; } else { throw new GetUser( userResponse.data); }
Call getUser
with a topology that differentiates the error types:
let userPromise = getUser(); // parameterized? userPromise.then(data => { do something with user data}); // chain promises on "success" as needed // split errors into a .then handler for server errors and a .catch handler for axios errors: userPromise.catch( something => { if( something instanceOf GetUserData) { return something.data; } throw something; // rethrow axios error }) .then ( data => { deal with unsuccessful server data}) .catch( error => { deal with axios error })
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.