async await with promises is then block required - javascript

How to basically async await properly? I have created a helper for AsyncStorage which async awaits automatically but do the users of this also have to use async await or promise approach to get the value?
This code works but unable to use the syntax correctly.
here is my code:
class AsyncStorageHelper {
static getItem = async (key: string) => {
let value: any = "";
try {
value = await AsyncStorage.getItem(key);
} catch (error) {
console.log(`Error item: ${value}`);
throw new Error(`Error ${value}`);
}
return value;
};
}
AsyncStorageHelper.getItem("logins")
.then(result => {
if (result) {
if (result === "1") {
navigate(SCREEN1);
} else {
navigate(SCREEN2);
}
}
})
.catch(err => {
navigate(LOGINSCREEN);
});
How can I convert the AsyncStorageHelper code to async await as depending on the result I want to navigate to different places.

await must be used inside a async function.
async function helper() {
try {
const result = await AsyncStorageHelper.getItem("logins");
if (result) {
if (result === "1") {
navigate(SCREEN1);
} else {
navigate(SCREEN2);
}
}
} catch (error) {
navigate(LOGINSCREEN);
}
}
helper()

Async functions and promise-returning function can be used externally in the same manner.
AsyncStorageHelper.getItem("logins")
.then(result => {
if (result) {
if (result === "1") {
navigate(SCREEN1);
} else {
navigate(SCREEN2);
}
}
})
.catch(err => {
navigate(LOGINSCREEN);
});
Is the same as:
// note: this code must run in another async function
// so we can use the keyword await
try {
const result = await AsyncStorageHelper.getItem("logins");
if (result) {
if (result === "1") {
navigate(SCREEN1);
} else {
navigate(SCREEN2);
}
}
} catch (err) {
navigate(LOGINSCREEN);
}
Note: your code has an unknown code path. What happens when AsyncStorageHelper.getItem("logins") returns a falsy value? You essentially have a noop and this might not be the desired behavior.

class AsyncStorageHelper {
static async getItem(key : string) {
let value: any = ""
try {
value = await AsyncStorage.getItem(key)
} catch (error) {
console.log(`Error item: ${value}`)
throw new Error(`Error ${value}`)
}
return value
}
}
try {
const result = await AsyncStorageHelper.getItem("logins")
if (result)
(result === "1") ? navigate(SCREEN1): navigate(SCREEN2)
} catch(err) {
navigate(LOGINSCREEN)
}

Related

Calling api request after Complete other requests

beforeTabSwitch: async (tab) => {
let flag = false;
if (tab === 'PAYMENT') {
if (this.isManualValidated) {
flag = true;
this.savePayment().then((response) => {
this.placeOrder();
});
}
}
return flag;
}
savePayment: async function () {
this.$http.post(this.savePaymentRoute)
.then(response => {
await this.getOrderSummary();
})
.catch(error => {
});
},
placeOrder: async function () {
this.$http.post(this.saveOrderRoute)
.then(response => {
})
.catch(error => {
console.log('placeOrder | ' + error);
})
},
When Place Order Button Clicked beforeTabSwitch() which validate data & then call savePayment() . as savePayment request is complete then call getOrderSummary() then call placeOrder() request.
Call in Order: savePayment() > getOrderSummary() > placeOrder()
but the issue is after execute savePayment() immediately placeOrder() execution start after complete then getOrderSummary() execute which is wrong.
i already try with Promises, callback but same issue.
You need to start writing some clean code. And you should either use promises approach or async-await approach. I hope this code help you:
beforeTabSwitch: async (tab) => {
if (tab !== 'PAYMENT') {
return false;
}
if (!this.isManualValidated) {
return false;
}
try {
const response = await this.savePayment();
this.placeOrder();
} catch (error) {
console.log(error);
}
return true;
},
savePayment: async function () {
try {
const paymentResponse = await this.$http.post(this.savePaymentRoute);
const summaryResponse = await this.getOrderSummary();
} catch (error) {
console.log(error);
}
},
placeOrder: async function () {
try {
const response = await this.$http.post(this.saveOrderRoute);
} catch (error) {
console.log('placeOrder | ' + error);
}
},

Class in Nodejs does not return expected value when using parameter

I have a class on my node server, each function of it returns something from another api, the first function that I will show does not use a parameter, it returns the items correctly, the second that uses the Make parameter, does not return anything, and does not point out error
function getInventory:
(this function works normally)
async getInventory() {
try {
let res = await axios.get(URL);
let data = res.data;
return data;
} catch (err) {
return err;
}
}
function getMakesNew(make): (this function works without errors but does not return anything)
async getMakesNew(make) {
try {
let res = await axios.get(URL);
let data = res.data;
let count = 0;
while (data != make) {
if (data[count].ID === make) {
return data[count].Name;
} else {
count++;
}
}
} catch (err) {
return err;
}
}
Calling the two functions on the routes:
// GetInventory
routes.get('/getInventory', async (req, res) => {
return res.json(await Vehicle.getInventory());
});
// getMakesNew
routes.get('/getMakesNew/:make', async (req, res) => {
let { make } = req.params;
return res.json(await Vehicle.getMakesNew(make));
});
function getMakesNew returns:
{}
return keyword is missing from your second function

Unable to access the data from inside the For Loop from the outside of the For Loop

I'm unable to access the array data pushed to the variable declared outside of the for loop.
let tickets = [];
(async () => {
for (let chunk of chunks) {
try {
let ticketChunk = await someMethod(chunk)
tickets.push(...ticketChunk)
console.log("first log", tickets)
} catch (error) {
console.error(error)
}
}
})();
console.log("second log", tickets)
The above code shows the array in the tickets variable properly on the first log, but the second log shows empty.
Assuming that chunks and ticketChunk are both arrays, and that someMethod() is allowed to be called in parallel, here's a much simpler and faster approach using map() and flat():
Promise.all(
chunks.map(async chunk => {
try {
const ticketChunk = await someMethod(chunk);
// some other async functions...
return ticketChunk;
} catch (error) {
console.error(error);
return [];
}
})
).then(ticketChunks => {
const tickets = ticketChunks.flat();
console.log(tickets);
});
If chunks or ticketChunk are not arrays, you can use generator functions to replicate the behavior above anyway:
function* map(iterable, callback) {
for (const value of iterable) {
yield callback(value);
}
}
function isIterable(arg) {
return typeof Object(arg)[Symbol.iterator] === 'function';
}
function* flat(iterable, depth = 1) {
for (const value of iterable) {
// value !== iterable prevents recursion on unit length strings
if (depth > 0 && isIterable(value) && value !== iterable) {
yield* flat(value, depth - 1);
} else {
yield value;
}
}
}
Promise.all(
map(chunks, async chunk => {
try {
const ticketChunk = await someMethod(chunk);
// some other async functions...
return ticketChunk;
} catch (error) {
console.error(error);
return [];
}
})
).then(ticketChunks => {
const tickets = [...flat(ticketChunks)];
console.log(tickets);
});
because your "main" function is asynchronous
Try :
let tickets = [];
for (let chunk of chunks) {
try {
let ticketChunk = await someMethod(chunk)
tickets.push(...ticketChunk)
console.log("first log", tickets)
} catch (error) {
console.error(error)
}
}
console.log("second log", tickets);
or
let tickets = [];
const someStuff = async() => {
for (let chunk of chunks) {
try {
let ticketChunk = await someMethod(chunk)
tickets.push(...ticketChunk)
console.log("first log", tickets)
} catch (error) {
console.error(error)
}
}
}
await someStuff();
console.log("second log", tickets);
You need to wait for the async function that you have to execute before trying to handle the data that was loaded in it. That would look a little something like this:
let tickets = [];
(async () => {
for (let chunk of chunks) {
try {
let ticketChunk = await someMethod(chunk)
tickets.push(...ticketChunk)
console.log("first log", tickets)
} catch (error) {
console.error(error)
}
}
})().then(() => {
console.log("second log", tickets)
});

Understanding promises

Let's say I have this 'pseudo'code
static async fetchAuthData () {
AsyncStorage.getItem('authtoken', (err, value) => AuthData.token = value)
.then( (value) => {
{ ...Ok token fetched... }
})
.catch( (err) => {
return Promise.reject('Some sort of error');
});
AsyncStorage.getItem('userid', (err, value) => AuthData.userid = parseInt(value))
.then( (value) => {
{ ...Ok userid fetched... }
})
.catch( (err) => {
return Promise.reject('Some sort of error');
});
if (token ok && userid ok ) {
return Promise.resolve('ok');
}
else {
return Promise.reject('Some sort of error');
}
}
I assume if (token ok && userid ok ) will not get executed until the previous two promises are resolved or rejected.
Am I right?.
Is there some possibility for if (token ok && userid ok ) get executed before I even get the token?.
This static method is called at the very beginning of my app and this is where I decide to go directly to the app or navigate to the auth flow.
The documentation doesn't seem to be clear about this.
Add await to the AsyncStorage functions to pause the execution till promise gets resolved and goes to next line
static async fetchAuthData () {
await AsyncStorage.getItem('authtoken', (err, value) => AuthData.token = value)
.then( (value) => {
{ ...Ok token fetched... }
})
.catch( (err) => {
return Promise.reject('Some sort of error');
});
await AsyncStorage.getItem('userid',(err, value) => AuthData.userid = parseInt(value))
.then( (value) => {
{ ...Ok userid fetched... }
})
.catch( (err) => {
return Promise.reject('Some sort of error');
});
if (token ok && userid ok ) {
return Promise.resolve('ok');
}
else {
return Promise.reject('Some sort of error');
}
}
as #Amadan said, It will get executed before you get the token
, you need to wait all the promises until they're resolve
static async fetchAuthData () {
try {
const [authtoken, userid] = await Promise.all([
() => AsyncStorage.getItem('authtoken'),
() => AsyncStorage.getItem('userid'),
]
if (token ok && userid ok ) {
return Promise.resolve('ok');
}
} catch(err) {
// handle exception
}
}
You can make use of async and await which makes code to execute in a synchronous way.
Check the below code which does the same.
static async fetchAuthData () {
try{
AuthData.token = await AsyncStorage.getItem('authtoken')
userId = await AsyncStorage.getItem('userid')
AuthData.userId = parseInt(userId)
return true;
}catch(err){
console.log(err)
return false
}
}
If any errors comes up it will be catched in catch block and return false from here.
static async fetchAuthData() {
await new Promise((resolve, reject) => {
AsyncStorage.getItem('authtoken', (err, value) => AuthData.token = value)
.then((value) => {
resolve('...Ok token fetched...')
})
.catch((err) => {
reject('Some sort of error');
});
})
await new Promise((resolve, reject) => {
AsyncStorage.getItem('userid', (err, value) => AuthData.userid = parseInt(value))
.then((value) => {
resolve('...Ok token fetched...')
})
.catch((err) => {
reject('Some sort of error');
});
})
if (token ok && userid ok) {
return Promise.resolve('ok');
} else {
return Promise.reject('Some sort of error');
}
}

How to properly format nested try/catch blocks inside a function that returns a server response

I have a function that is called that must return a response to a server. Inside this function are two await function calls that are nested. To track error handling, I added try/catch blocks. Is there a way to avoid having nested try catch blocks to track all cases where the function might fail so I can send back an error server response?
Here's my function, it queries for a user's unique device id's and sends a push notification to each one. If a token becomes invalid, then I delete it from my database:
function findUserDevices(uid: string, message) {
collectionData(fb.firestore().collection('devices').where('userId', '==', uid)).pipe(
filter((userDevices) => userDevices && userDevices.length > 0),
take(1)
).subscribe( async (devices: any) => {
var userDeviceTokens: string[] = devices.map((device: any) => device.token);
if (userDeviceTokens !== undefined && userDeviceTokens.length != 0) {
try {
message['tokens'] = userDeviceTokens;
const pushResponse = await admin.messsaging().sendMulticast(message);
if (pushResponse.failureCount > 0) {
const failedTokens = [];
pushResponse.responses.forEach((resp, idx) => {
if (!resp.success) {
failedTokens.push(userDeviceTokens[idx]);
}
});
failedTokens.forEach( async (token) => {
var tokenInstanceID = token.split(':')[0];
try {
await deleteOldToken(tokenInstanceID);
console.log(`Token ${tokenInstanceID} deleted`)
} catch {
return res.status(500).send("err");
}
})
return res.status(200).send("ok");
} else {
return res.status(200).send("ok");
}
} catch {
return res.status(500).send("err");
}
} else {
return res.status(200).send("ok");
}
})
}
It just feels a bit excessive with all the returns I must have. Where can I improve?
EDIT, broke apart code into three blocks to prevent arrow coding
function findUserDevices(uid: string, message) {
collectionData(fb.firestore().collection('devices').where('userId', '==', uid)).pipe(
filter((userDevices) => userDevices && userDevices.length > 0),
take(1)
).subscribe(async (devices: any) => {
var userDeviceTokens: string[] = devices.map((device: any) => device.token);
if (userDeviceTokens !== undefined && userDeviceTokens.length != 0) {
try {
message['tokens'] = userDeviceTokens;
const response = await admin.messaging().sendMulticast(message);
const oldTokensArray = checkOldTokens(response, userDeviceTokens);
if (oldTokensArray.length > 0) {
await deleteOldTokens(oldTokensArray);
return res.status(200).send("ok");
} else {
return res.status(200).send("ok");
}
} catch (err) {
return res.status(500).send(err);
}
} else {
return res.status(200).send("ok");
}
})
}
function checkOldTokens(response, userDeviceTokens) {
if (response.failureCount > 0) {
const failedTokens = [];
response.responses.forEach((resp, idx) => {
if (!resp.success) {
failedTokens.push(userDeviceTokens[idx]);
}
});
return failedTokens;
} else {
return [];
}
}
async function deleteOldTokens(tokenArray) {
for (const token of tokenArray) {
await fb.firestore().collection('devices').doc(token).delete();
}
}

Categories

Resources