I've got a function that makes a call with axios and returns it:
const makeRequest = () => {
return axios.get('/data');
}
const printResponse = () => {
makeRequest()
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
}
I'm trying to use async await to make this better and avoid using 'then'.
const makeRequest = async () => {
return await axios.get('/data');
}
const printResponse = () => {
try {
const response = makeRequest();
console.log(response)
} catch(error) {
console.log(error)
}
}
However, despite using await, makeRequest still returns a promise, so I have to end up using then in my printResponse function anyway. Am I not using this correctly?
"However, despite using await, makeRequest still returns a promise"
Yes, of course it does. async/await is just syntactic sugar for working with Promises. In particular, any function marked async will return a Promise - this is by design.
If you don't like using .then, you can just as easily use async/await to consume this promise:
const printResponse = async () => {
try {
const response = await makeRequest();
console.log(response)
} catch(error) {
console.log(error)
}
}
Related
I made this store:
export class CommentStore {
comments = []
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
async loadPostComments(postId: number): Promise<void> {
const res = await API.loadPostComments(postId);
runInAction(() => {
this.comments = res;
});
}
async sendComment(postId: number, comment: Comment): Promise<void> {
try {
await API.sendComment(postId, comment);
await this.loadPostComments(postId);
return true;
} catch (err) {
console.log('oops');
}
}
}
Do i need use await in react components? For example:
useEffect(() => {
(async function () {
await loadPostComments(postId);
})();
}, [loadPostComments, postId]);
But this also works fine:
useEffect(() => {
loadPostComments(postId);
}, [loadPostComments, postId]);
Same for sendComment onClick:
onClick={()=>{sendComment(postId, comment)}}
onClick={async ()=>{await sendComment(postId, comment)}}
So, is it necessary to use await in this situations?
You want to await something only if it is necessary, e.g. when the next line of code uses the data from Promise.
In the useEffect case that you provided it is not necessary and on onClick handlers as well
Yes it is unnecessary to write async/await on them.
you just have to write the async call on the functions and that is enough.
for example:
const [posts, setPosts] = useState([]);
useEffect(() => {
const loadPost = async () => {
// Await make wait until that
// promise settles and return its result
const response = await axios.get(
"https://jsonplaceholder.typicode.com/posts/");
// After fetching data stored it in some state.
setPosts(response.data);
}
// Call the function
loadPost();
}, []);
`
there is no need to write promise and async / await on everything, remember ;P
What's the proper way of returning the data not the promise object as the code snippet below does?
const getData = async () => {
try {
const res = await fetch(API_ENDPOINT);
const data = res.json();
return data;
} catch (error) {
ToastAndroid.show(error, ToastAndroid.LONG);
}
};
console.log(getGeneralData());
Async Functions return a promise, you need to use :
getData().then(res=>console.log(res);
You can wrap your code in "self invoked" function (async function() {....})() and it allows you to use await for awaiting result of getData().
(async function() {
const getData = async() => {
try {
const res = await fetch(API_ENDPOINT);
const data = res.json();
return data;
} catch (error) {
ToastAndroid.show(error, ToastAndroid.LONG);
}
};
console.log(await getData());
})();
The async function is just syntactic sugar for a Promise. You can call the .then() method to handle resolving the promise.
const API_ENDPOINT = 'https://jsonplaceholder.typicode.com/posts/1/comments';
const getData = async () => {
try {
const res = await fetch(API_ENDPOINT);
return res.json();
} catch (error) {
ToastAndroid.show(error, ToastAndroid.LONG);
}
};
getData().then(data => console.log(data));
.as-console-wrapper { top: 0; max-height: 100% !important; }
Introduction
I am new in the world of javascript promises and I need to understand how they work correctly...
Until know I have been doing this in my code:
const handleRefresh = () => {
setIsRefreshing(true);
fetchUserData()
.then(async () => { <--------- Using then because I return a promise in fetchUserData
await fetchUserPosts(); <------- Using await here
setIsRefreshing(false);
}).catch(err => { <--------- This will catch the error I have thrown in the function fetchUserPosts or inside the then body
// TODO - Show error
setIsRefreshing(false);
console.log(err)
);
};
const fetchUserData = async () => { <------ async function
const { firebase } = props;
const userId = firebase.getCurrentUser().uid;
const documentRef = firebase.getDatabase().collection("users").doc(userId);
// Fetch all the user information
return documentRef <--------- Returning the promise here
.get()
.then((doc) => {
if (doc.exists) {
// Get all user data
const data = doc.data();
console.log(data);
setUserData(data);
}
})
.catch((err) => {
throw err; <----------- Throwing error
});
};
I don't know if I am doing anti patterns... But basically I need to know if this is a good way and if I am doing this correctly.
Questions
Do I have to declare the fetchUserData function as async to return a promise?
Can I use the async await in the then/catch body?
Can I do this?
const handleRefresh = async () => {
setIsRefreshing(true);
await fetchUserData()
.then(async () => { <--------- Using then because I return a promise in fetchUserData
await fetchUserPosts(); <------- Using await here
}).catch(err => { <--------- This will catch the error I have thrown in the function fetchUserPosts or inside the then body
// TODO - Show error
console.log(err)
);
setIsRefreshing(false);
};
I would really appreciate if someone guides me. Thanks.
the words async and await are only syntactic sugar for then and catch.
This:
fetchUserData()
.then(data => return data )
.catch(error => return error)
is equivalent to:
async function getUserData() {
const userData = await fetchUserData()
return userData
}
Here you are returning anything (success or error). If you want to treat the error here, just put a try/catch clause.
async function getUserData() {
try {
return await fetchUserData()
} catch (e) {
return e.message
}
}
Note that you can only use the await clause within an async function.
1.
Function can return Promise without being declared as async as long as you don't await inside it,
2.
You should not use async-await inside then, simply return a Promise and it'll be resolved in the following then,
3.
When using async-await syntax, Promises are awaited in a declarative way as demonstrated below:
const handleRefresh = async () => {
try
{
const a = await getA()
// pass the result to another Promise
const b = await getB(a)
const c = await getC(b)
} catch (error)
{
handleError(error)
}
};
I'm trying to wire redux-thunk into Next.js and it works fine if my thunk returns a promise. How do I convert that to use async/await? I took a look at this article (how to async/await redux-thunk actions?) but I'm having trouble wrapping my head around it.
My getInitialProps in my index.js is
static getInitialProps(props) {
const {store, isServer} = props.ctx;
if (!store.getState().placeholderData) {
return store.dispatch(loadData());
}
and currently my action that handles loading the data is
export const loadData = () => (dispatch) => {
return isoFetch(homeES_endpoint)
.then(res => res.json())
.then(data => dispatch(loadDataSuccess(data)))
.catch(err => console.error('error loading data', err.toString()));
}
How might I convert loadData to use async/await? I've tried
export const loadData = () => async (dispatch) => {
try {
const res = await isoFetch(homeES_endpoint);
const data = await res.json();
dispatch(loadDataSuccess(data));
} catch(error) {
//dispatch({ type: LOGIN_ERROR, error });
console.error('error loading data',error.toString())
}
}
but the main getInitialProps in '_app.js' doesn't wait for it.
It's not specific to redux-thunk. async..await is syntactic sugar for promises. Once you know how exactly it works, it can be applied to any situation. await is a substitute for .then(...). try..catch is a substitute for catch(...):
export const loadData = () => async (dispatch) => {
try {
const res = await isoFetch(homeES_endpoint);
const data = await res.json();
const result = await dispatch(loadDataSuccess(data));
return result;
} catch (err) {
console.error('error loading data', err.toString()));
}
}
The difference is that dispatch(...) is returned from then and thus a proper translation needs it to be awaited. A known pitfall of async..await is that if a promise is returned with return dispatch(...), it won't be handled with try..catch.
I have an array of objects that I'm looping over and calling a function with them as the argument. It's an async/await function, and I'd like to create a PromiseAll that resolves when all of the async/await calls have concluded. I've used an array map to convert them to promises, but the promises resolve instantly and don't wait until all await calls have been made.
async function runTest({_id, name, live, dev}) {
(async () => {
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
} catch(error) {
await browser.close()
} finally {
await browser.close()
return
}
})();
}
module.exports = (tests) => {
let testPromises = tests.map((test) => {
return runTest(test).then(function (res) {
return console.log(res, 'done')
})
});
Promise.all(testPromises).then((data) => {
console.log('Done resolving')
}).catch(function(err){
})
}
What is the correct way to guarantee that all of the array objects have passed through the function and completed processing before resolving the PromiseAll? I'm not hugely familiar with async/await.
You dont need an async IIFE as i already mentioned in comments. More over your code can be simplified like so:
async function runTest({_id, name, live, dev}) {
// we can have one try/catch since you close browser at any error
try{
const browser = await puppeteer.launch();
const page = await browser.newPage();
}
catch(error) {
return await browser.close()
}
}
module.exports = async (tests) => {
try{
const data = await Promise.all(tests.map(test => runTest(test)));
console.log('Done resolving')
}
catch(e){ console.log(e)}
}
I think you may be missing a return statement in runTest, though I don't know why you need the anonymous async function in the first place, like #TheReason mentioned:
async function runTest({
_id,
name,
live,
dev
}) {
return (async () => { // here
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
} catch (error) {
await browser.close()
} finally {
await browser.close()
return
}
})();
}
The straightforward approach:
function launch() {
return new Promise(function(resolve, reject) {
setTimeout(resolve, 5000, 'blast off!')
})
}
async function doSomething(id) {
const message = await launch()
return `${message} [${id}]`
}
let runs = [10, 20, 30].map(doSomething)
Promise.all(runs).then(function(values) {
console.log(values)
})
//outputs
[ 'blast off! [10]', 'blast off! [20]', 'blast off! [30]' ]