this await throwing unexpected token error - javascript

I have a simple async function. It just sends a request and returns the data:
export const updatePanorama = async ({ commit }, payload) => {
const urlEnd = '/v1/pano/update'
const type = 'post'
const resp = await api.asyncRequest(urlEnd, type, payload)
commit('SET_PANORAMA', resp.data)
return resp
}
And this is how I'm using the function:
handleUpdatePanorama (panorama) {
const payload = {}
this.updatePanorama(payload).then(resp => {
this.setIsLoading(false)
this.handleAlert('updateSuccess', 'success')
}).catch(() => {
this.setIsLoading(false)
this.handleAlert('updateError', 'danger')
})
},
The problem is, the code after catch runs if there's an error inside then. But this way I don't know whether the catch error is an request error or and error triggered by the code inside then.
I'm trying try and catch to solve that problem:
handleUpdatePanorama (panorama) {
try {
const payload = {}
const resp = await this.updatePanorama(payload)
console.log('resp:', resp)
this.setIsLoading(false)
this.handleAlert('updateSuccess', 'success')
} catch (err) {
this.setIsLoading(false)
this.handleAlert('updateError', 'danger')
})
},
However, I get an unexpected token error in this line: await this.updatePanorama(payload)
What am I doing wrong?

The problem is, the code after catch runs if there's an error inside then
The solution for that is to not use catch, but the second then parameter. Have a look at the difference between .then(…).catch(…) and .then(…, …) for details.
I'm trying try and catch to solve that problem
That won't work, the catch clause will still be called if there's an exception thrown by setIsLoading or handleAlert.
I get an unexpected token error. What am I doing wrong?
You have not declared the handleUpdatePanorama method as async.
To mitigate the issues and fix the syntax, you could write
async handleUpdatePanorama (panorama) {
var result
try {
const payload = {}
const resp = await this.updatePanorama(payload)
console.log('resp:', resp)
result = ['updateSuccess', 'success']
} catch (err) {
result = ['updateError', 'danger']
} finally {
this.setIsLoading(false)
}
this.handleAlert(...result)
},

If you need to handle errors specifically from updatePanorama, use the second argument to .then(onSuccess, onError)
handleUpdatePanorama(panorama) {
const payload = {}
this.updatePanorama(payload).then(resp => {
this.setIsLoading(false)
this.handleAlert('updateSuccess', 'success')
}, err => {
// handle error from updatePanorama
// you can throw err if you also want to handle the error in .catch()
}).catch(() => {
this.setIsLoading(false)
this.handleAlert('updateError', 'danger')
})
}
note: if you return (or have no return statement) from the error handler, any subsequent .then(onSuccess will execute, if you throw an error (or return Promise.reject() for example, then the .catch() code will also run

Related

Defining a variable inside the try block of the useQuery function (tanstack's react-query)

I encountered a weird issue where I couldn't define a variable inside an anonymous function which had a try catch block defined in it.
let response: AxiosResponse<CustomType[]>; // had to define outside the useQuery
const { data: info } = useQuery(
['queryKey', a, b],
async () => {
// let response: AxiosResponse<CustomType[]>; //ERROR variable response is used before being assigned
try {
response = await getAxios().get(`requestURL`);
const responseFiltered = {};
response.data.forEach((a) => {
responseFiltered[a] = a;
})
return responseFiltered;
} catch (error) {
logger.error({
meta: { error, response}, // variable used here
});
}
}
);
Not sure why it expects the response variable to be defined outside the useQuery function.
You are telling the compiler that response will be of type AxiosReponse. However, you are not giving response a "value" in branches. response is assigned inside the try/catch, so in the catch clause, it might still be undefined. That's what TypeScript is trying to tell you.
To fix this, define your response as being potentially undefined:
let response: AxiosResponse<CustomType[]> | undefined
Then you can use it in the catch block. Even though, very likely, in the catch block it will be undefined if the network request fails.
With axios, the error is actually an AxiosError, which will contain the response, so maybe you'd want something like this?
const { data: info } = useQuery(
['queryKey', a, b],
async () => {
try {
const response = await axios.get(`requestURL`);
return response;
} catch (error) {
if (axios.isAxiosError(error)) {
console.error({
meta: { error, response: error.response },
});
}
throw error
}
}
);
Please further keep in mind that catching an error just to log it is not ideal with react-query, because it "swallows" the error. You can see that I've re-thrown the error at the end of the catch block. A better approach would be to use the onError callback:
const { data: info } = useQuery(
['queryKey', a, b],
async () => {
return await axios.get(`requestURL`);
}, {
onError: (error) => {
if (axios.isAxiosError(error)) {
console.error({
meta: { error, response: error.response },
});
}
}
})

Mock a thrown exception

Is there a way to mock what a thrown exception in the try catch block? I want to test my function that the url string in error.message is indeed replaced with replacedURL string. How can I easily test it or mock the thrown exception to an object with this URL.
async function getUsers() {
try {
const response = await fetch('/api/users');
if (response.status >= 400) {
console.error('Could not fetch users');
return;
}
const users = response.json();
return users;
} catch (error) {
let message = error.message;
if (message) {
message = message.replace(/https:\/\/some.url.com /g, 'replacedURL');
delete error.message;
}
console.error('error', error);
}
}
Here's my test
test('url in error message is replaced', () => {
expect(getUsers()).toThrow('replacedURL');
})
You might want to actually throw an error in your function for it to be caught by toThrow.
Also, I'd recommend that your test doesn't actually tries fetching from the API (unless you're sure that's what you want it to do). Instead, consider using a custom caller (which can extend fetch) which you can then mock the response for, like const caller = jest.fn().mockRejectedValue({ message: 'https:://some.url.com' });

How to use a conditional validation after Axios call in Vue app

I have a Vue application where I make a POST request to my backend. I am now trying to call a validation method after the response from my backend returned back an error to my frontend. But for some reason my code is not executed:
UPDATED QUESTION CODE:
validateFormInput(){
this.$refs.form.validate()
},
saveSelectionVoter() {
var pageURL = window.location.href;
var lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
this.votersSelectArray.voterAvailableTimes = [...this.votersSelectArray.voterAvailableTimes, ...this.selected]
console.log(JSON.stringify( this.votersSelectArray))
axios.post("http://localhost:8080/api/votercontroller/",
this.votersSelectArray,
{
params: {
meetingName: lastURLSegment,
}
},
).then(function(response){
})
.catch(function (error){
this.validateFormInput()
console.log(error)
})
this.selected = []
},
This causes a new error:
TypeError: Cannot read property 'validateFormInput' of undefined
always have a catch to see the error return
axios return you a promise so it captures the error if there is any
axios.post('url')
.then((res) => {
// do somthing
}).catch(err){
console.log(err)
}
You can either use the callback method to catch the response/error or use the Promise way, which is my favorite because of scope and readability.
You start by declaring your function with async
async saveSelectionVoter() {
Then you use a try/catch block to handle the response/error:
try{
const response = await axios.post(url, params)
// handle response here
} catch (error) {
// handle error here
}

Best way to use asyn/await in the following code

I am kind of new in Javascript and I want to connect to DB and run a script. Then get the result of script and run functions in order.
If there is any error with one of the functions, it should stop and doesnt run other functions.
I tried the following:
const {
Client
} = require('pg')
const client = new Client({
'connection info'
})
client.connect()
.then(() => console.log('DB connected'))
.catch(err => console.error('connection error', err.stack))
let dbResult
const data = async() => {
try {
dbResult = await client.query('SCRIPT') // array of json
} catch (error) {
console.log(error);
}
}
const func1 = async() => {
try {
// do something with dbResult
console.log('func1 success msg')
} catch (error) {
console.log('error in func1')
}
}
const func2 = async() => {
try {
// do something with dbResult
console.log('func2 success msg')
} catch (error) {
console.log('error in func2')
}
}
const func3 = async() => {
dbResult.forEach(result => {
// do something
})
try {
// do something with dbResult
console.log('func3 success msg')
} catch (error) {
console.log('error in func3')
}
}
data()
func1()
func2()
func3()
All the functions you call are async, therefore return Promises and should be awaited. You can await all of them in a try/catch block, so if one fails, the others won't execute.
Don't use try/catch in each individual function, but rather here :
const data = async() => client.query('SCRIPT') // array of json
const func1 = async() => console.log('func1 success msg')
const func2 = async() => console.log('func2 success msg')
const func3 = async() => dbResult.forEach(result => console.log(result))
(async () => {
try{
await client.connect();
let dbResult = await data();
dbResult = await func1(dbResult);
await func2();
await func3(dbResult);
} catch(err) {
console.log(err);
}
})();
await Promise.all([data, func1, func2, func3]) would also fail if one of the Promises failed, but does not guarantee the execution order.
Below is if you must use try catch inside each of your function body. If not, then I'd stick with the answer from Jeremy above.
What you can do is instead of console logging your errors that you receive in try..catch block, you can throw new error, which will stop the execution of your code and console log the actual error.
(Well, not exactly console log, but rather console.error() it)
This will prevent the execution of other functions, unless you do something with your error (make some error handling where you can execute another code, depending on the error).
In general, the syntax for this as follows:
try {
await someStuff();
} catch (err) {
throw new Error(err)
}
Object err has some additional properties, such as name and message.
Here is more about Error object.

Throw Error with loop of await function

I'm struggling with a loop of async await function. I'm creating an API which POST a request to another API. I have to make a loop because users could insert many items at once in the database.
The API that I call rejects Parallel executions so I can't use Promise.all :/
In order to implement that service I made a function to insert one object :
const addValue = async (ID:number, cookie: string) => {
try {
const addValueBody = await addValueQuery(ID:number)
const header = { 'cookie': cookie, 'content-type': 'application/json' }
const fetchResult = fetch('http://api-to-call.xyz', { method: `POST`, headers: header, body: addValueBody })
const response = await fetchResult
const jsonData = await response.json()
return jsonData
} catch (e) {
throw Error(e.message)
}
}
And a function which will execute addValue inside a for loop :
const addMulti = async (values: any, cookie: string) => {
for (const item of values) {
await addValue(item.ID, cookie)
}
}
The problem is that when I call addMulti and if there is an Error I have a UnhandledPromiseRejectionWarning.
Also I tried to put de for ... in or await addValue inside a try catch but it doesn't catch the Error(s)
Hence, I have 2 questions :
How can I throw en Error if it occurs during the execution of the loop ?
Is it possible to break the loop if there is an error ?
Thanks for your help :)
How can I throw en Error if it occurs during the execution of the loop ? Is it possible to break the loop if there is an error ?
Your code does that already, by awaiting addValue. If addValue throws an error, since addMulti doesn't catch, it terminates addMulti as well.
The problem is that when I call addMulti and if there is an Error I have a UnhandledPromiseRejectionWarning.
The code you've shown is correct¹, the problem is that it appears you have no error handling on the call to addMulti. That code must either:
Handle errors from it (via try/catch in an async function if you don't want to allow it to propagate, or via the catch method if using the promise directly), or
Propagate the error to something that will handle it (by not catching it in an async function, or by returning the promise in a non-async function)
So for instance, if the call to addMulti is in a non-async function and if nothing calling that function will handle errors, you need to handle it at that stage:
addMulti(/*...*/)
.catch(error => {
// ...handle/report the error
});
If it's in an async function but nothing handles that async function's errors, then:
try {
await addMulti(/*...*/);
} catch (e) {
// ...handle/report the error
}
¹ ...other than it seems odd to catch e and then do throw Error(e.message); just let the error propagate.
When you get UnhandledPromiseRejection working with async functions, it almost surely means that you didn't catch the thrown error. In your case you could just wrap the whole loop in try{...} catch{...} block:
const addMulti = async (values: any, cookie: string) => {
try {
for (const item of values) {
await addValue(item.ID, cookie)
}
} catch(e) {
console.log('Error occured in async function')
}
}

Categories

Resources