I am using AsyncStorage in my React Native application to store information about the user. The getItem() function is asynchronous and requires me to implement a callback when I want to load data from the storage system.
AsyncStorage.getItem("phoneNumber").then((value) => {
this.setState({"phoneNumber": value});
}).done();
Because retrieving a value from the storage does not take long, I would like to wait until the operation is complete before continuing execution.
Is it possible to load data in a way that is not Asynchronous? If not, is there an easy way for me to wait until the getItem() call is complete to continue executing?
You can try either add a then after your getItem.
AsyncStorage.getItem("phoneNumber").then((value) => {
this.setState({"phoneNumber": value});
})
.then(res => {
//do something else
});
Or use await to wait the async operation to finish
var value = await AsyncStorage.getItem(STORAGE_KEY);
//use value to do something else.
try this option and you will not get the
Syntax Error: Await is a reserved word
async getData() {
return await AsyncStorage.getItem("#App:KEY");
}
You can try this:
async getPhoneNumber() {
const phoneNumber = await AsyncStorage.getItem("phoneNumber")
console.log(phoneNumber)
}
Related
i wrote an application in VueJS and i have to send first a get call to get the redirect url.
this.$axios.get('http://first-url.call').then(function(response) {
console.log(response.request.res.responseUrl)
let postUrl = response.request.res.responseUrl
}).catch(function(error){
console.log(error)
});
In my next call i want to use the "response.request.res.responseUrl" as post url
this.$axios.post(postUrl).then(function(response) {
console.log(response);
}).catch(function(error){
console.log(error)
});
Unfortunately, i cannot save the "response.request.res.responseUrl" response in a js variable. I'm not so familiar with async / await so maybe someone can help how i can store the first response into a value that i can use in my second call?
It's simpler to write it exclusively with async..await syntax:
try {
let response = await this.$axios.get('http://first-url.call')
let postUrl = response.request.res.responseUrl;
response = await this.$axios.post(postUrl)
...
} catch (err) {
...
}
It's beneficial to know the exact meaning of it. The key is correct promise chaining:
this.$axios.get('http://first-url.call')
.then((response) => {
let postUrl = response.request.res.responseUrl;
return this.$axios.post(postUrl)
})
.then((response) => {...})
.catch(...);
This way promises are executed in correct order and don't have unnecessary nested callbacks.
Be aware of incorrect use of function, it will lead to this problem.
Here is a solution without async/await: Make the second axios call within the first successful call. You need to use arrow functions for this so you keep the correct this on your Vue instance:
this.$axios.get('http://first-url.call').then((response) => {
console.log(response.request.res.responseUrl)
let postUrl = response.request.res.responseUrl
this.$axios.post(postUrl).then((response) => {
console.log(response);
}).catch(function(error){
console.log(error)
});
}).catch((error) =>{
console.log(error)
});
There are a number of ways to deal with this.
The simplest is to create a variable outside the callbacks. Though the following still relies on your first call completing before the second one.
let postUrl = null
this.$axios.get('http://first-url.call').then(function(response) {
postUrl = response.request.res.responseUrl
})
The next best (really the best) solution is to use async/await instead of .then() so you don't have callback scoping issues. This approach also guarantees you won't have a race condition because it will "await" for the first call to finish before making the second call.
The following would need to take place inside a function with async.
async function doWhatever() {
const response = await this.$axios.get('http://first-url.call')
const postResponse = await
this.$axios.post(response.request.res.responseUrl)
}
Finally, the last option is you nest your callbacks. This allows the second callback to have access to the scope of the first callback.
this.$axios.get('http://first-url.call').then(function(response) {
this.$axios.post(response.request.res.responseUrl).then(function(postResponse) {
// do something with the postResponse
})
})
Also, while the above code will work, it's usually better to chain promises.
this.$axios.get('...')
.then(function(response) {
// we return the promise so it can be handled in the next .then()
return this.$axios.post(response.request.res.responseUrl)
})
.then(function(postResponse) {
// do something with the postResponse
})
Notice how this last example starts to look a lot like async/await.
I am developing a react native app and I would like data persistence. Async storage is working fine as I expect it to, however the problem is that I initialize a key 'servers' in a component and and call the setItem function in componentDidMount function. Now because of this every time I terminate the app and run it again all the data from the previous session is removed as the 'servers' key is reset when the component is mounted. I understand why this is causing the problem so I want to know where should I set the key in my code that it will not reset on every time my component mounts.
This is the function that I call in componentDidMount. This is the only way to declare a key in Async storage correct? because without it I would not be able to call getItem.
const save = async () => {
try {
server_list = await AsyncStorage.setItem('server_list', JSON.stringify({servers: []}));
}
catch (e){
console.log("Failed to load")
}
}
You can achieve this by filling the AsyncStorage only as long as there is no data under the server_list key.
This would look like this:
setServerList = async (value) => {
try {
const serverList = await AsyncStorage.getItem('server_list');
if(serverList === null) {
await AsyncStorage.setItem('server_list', value)
}
} catch(e) {
// save error
}
console.log('Done.')
}
You can still call this in the componentDidMount and your server list will no longer be overwritten
I have an async / await process like below
async function getFirebaseToken() {
firebase_token = await iid().getToken();
}
since this is an async operation, We cannot say when this process is completed. I do not want to continue to next step until i get the firebase_token. For this I have gone through this solution . But it didn't work for me.
Any suggestion on How to wait for the async/await process untill getting the result?
the calling function will either need to be called with in async function with await, or use the .then at the "top" of the calling functions
for example, if you are fetching the token on click
const handleClick = () => {
//async functions return a promise. Handle the end-of-line here
getFirebaseToken()
.then(token => { //do something with the token})
.catch(error => {//handle the error})
}
the async function return a promise, which is handled in the onClick button. the return value will be available as "token" in the above promise handler
async function getFirebaseToken() {
firebase_token = await iid().getToken();
//this will be available in the .then function, as token
return token;
}
I'm trying to make an ajax call in a loop. But it looks like we can't, so i'm wondering how can i avoid this situation.
I'm making a search, and i have this method who format the data :
async formatSearchUserByNameResults(results) {
if (results.length > 0) {
results.forEach((element) => {
const currentUserData = await user.getUserById(element.id);
const aResult = searchBuilders.userBuilder(element);
aResult.following = currentUserData.folliwing;
this.searchResults.push(aResult);
});
}
},
The getUserById function make an ajax call :
async getUserById(userId) {
const response = await axios.get(`${config.baseUrl}/users/${userId}`, { withCredentials: true });
return response.data;
}
But i always get this error :
Parsing error: await is a reserved word
Because forEach is synchronous.
Is there any alternative to make an ajax call in a loop ?
Thanks
I'm not sure why you get that particular error but one issue could be that the anonymous function you're passing into the forEach() is not an async function.
Try async (element) => { ...
I would avoid having async functions where you're not tracking the result of whether they're complete. You could probably wrap them into a Promise.all() or something like that to know if they've completed or not.
verifyUser which awaits verifyUserSignInSuccess which awaits userSnapshot which awaits user
Here in these two functions, which will be more effective in terms of correctness, memory, time for ReactNative app :
export function verifyUser() {
return async dispatch => {
dispatch(verifyUserSignInRequest());
try {
const user = await firebase.auth().onAuthStateChanged();
if (user) {
let userRef = "/user/" + user.uid;
const userSnapshot = await firebase
.database()
.ref(userRef)
.once("value");
dispatch(verifyUserSignInSuccess(userSnapshot.val()));
} else {
dispatch(verifyUserSignInFailure(USER_NOT_SIGNED_IN));
}
} catch (e) {
dispatch(verifyUserSignInFailure(e.message));
}
};
}
Or the Nested Async Await :
export function verifyUser() {
return async dispatch => {
dispatch(verifyUserSignInRequest());
try {
await firebase.auth().onAuthStateChanged(async user => {
if (user) {
let userRef = "/user/" + user.uid;
await firebase
.database()
.ref(userRef)
.once("value")
.then( () => {
dispatch(verifyUserSignInSuccess(userSnapshot.val()));
});
} else {
dispatch(verifyUserSignInFailure(USER_NOT_SIGNED_IN));
}
});
} catch (e) {
dispatch(verifyUserSignInFailure(e.message));
}
};
}
According to the documentation, the onAuthStateChanged() function returns
The unsubscribe function for the observer.
So you can just:
var unsubscribe = firebase.auth().onAuthStateChanged((user) {
// handle it for changes signed in, signed out, or when the user's ID token changed in situations such as token expiry or password change
});
And then:
unsubscribe(); for registering the for observer.
onAuthStateChanged is a Observer which calls the observer when users were signed in, signed out, or when the user's ID token changed in situations such as token expiry or password change . so the second one is the best solution . every login or change .
` let userRef = "/user/" + user.uid;
await firebase
.database()
.ref(userRef)
.once("value")
.then( () => {
dispatch(verifyUserSignInSuccess(userSnapshot.val()));
});
} else {
dispatch(verifyUserSignInFailure(USER_NOT_SIGNED_IN));
}`
that is correct to cross check is user is valid or not .i dont't thinks there is memory comparison is required.
Time - Since all your async functions need to run one after the other whichever method u use async/await or promise chaining or a mix up of both will take same time only.
Correctness - Both are correct logically and will work the same. But async/await is the latest addition to JS to solve the problem of promise chaining. Promise chaining leaves the code hard to read. Better U stick to async/await.For situations where u need to run two async functions parallelly, use await Promise.all() etc. In the end, it's your personal preference.
Memory? - I have no idea on that
Read this book its free on github which contains details on promises, async functions, async/await etc.
https://github.com/getify/You-Dont-Know-JS