Async function Uncaught (in promise) undefined error - javascript

I'm trying to do some validations before creating/updating an entry as shown below:
async save(){
return new Promise((resolve, reject)=>{
if(!this.isCampaignValid){
this.handleError()
reject()
}
else{
this.$store
.dispatch('updateCampaign')
.then((res)=>{
resolve()
this.showNotification(res.message, 'success')
})
.catch(error=>{
this.showNotification(error.message, 'error')
reject()
})
}
})
},
the isCampaignValid is a computed value which computes the validity.
If the campaign is not valid, then I'm getting an error in the console as below:
Uncaught (in promise) undefined
The this.handleError() function works too. How can handle this promise error situation?

Just in case handleError() throws, try:
if (!this.isCampaignValid) {
try {
this.handleError()
} catch (e) {
console.error(e);
}
reject()
}

First of all, you don't need to return a promise in an async function. It implicitly returns one, resolving with the value returned by the function or rejecting with the error object if the function throws. Although you could return a promise and JS unpacks it for you, it's unneeded code.
That said, because async returns a promise, you'll have to catch that promise too. Since your first conditional block just throws an error but doesn't catch it, the promise returned by save will reject. You need to handle that rejection.
Here's a simplified version of your code to see where it's happening.
async save(){
if(!this.isCampaignValid){
this.handleError()
// Throwing an error in an async function is equivalent to a reject.
throw new Error('Campaign is not valid') // Here
}
else{
try {
const res = await this.$store.dispatch('updateCampaign')
this.showNotification(res.message, 'success')
} catch (e) {
this.showNotification(error.message, 'error')
}
}
},
// When you call save, catch the error
yourObject.save()
.then(() => {...})
.catch(() => {...})
// If your call is in an async function, you can try-catch as well
try {
await yourObject.save()
} catch(e) {
// It failed.
}

Related

Why isn't react component catching axios error

I have the following code on python using flask
#bp.route("/test", methods=["GET"])
def test():
throw_error = True
if throw_error :
return jsonify(message="Throwing an error"), 405
return jsonify(message="Test message"), 200
on React I have a context setup with the following function
function testRequest(){
const response = axios.get('/api/test')
console.log(response)
}
I'm calling this function on a button click in another component by
async function handleButtonClick(e){
e.preventDefault();
try{
await testRequest();
}catch(error) { // DOESN'T EXECUTE??
console.error("Error occured")
setError("Error occurred in test method")
}
}
Why isn't the try catch, catching the 405 error?
You can only usefully await a promise. testRequest doesn't return a promise.
It triggers axios.get, assigns the promise to response, logs it, then returns undefined.
The try/catch doesn't touch the promise at all.
You could fix that with:
function testRequest(){
const response_promise = axios.get('/api/test')
console.log(response_promise)
return response_promise;
}
So the promise is being awaited inside the try/catch.
With below modification to your function, you will be able to catch error.
async function testRequest() {
const response = await axios.get('http://localhost:1337/sample/test');
return response;
}
async function handleButtonClick(e:any) {
e.preventDefault();
try {
await testRequest();
} catch (error) { // DOESN'T EXECUTE??
console.error("Error occured")
console.log(error.mes);
}
}

Handling Promise rejection with catch while using await

I am using await to make the code cleaner, but I am not sure whether I am handling exceptions correctly.
An example while using azure-devops-node-api;
const foo = async() => {
return new Promise((resolve, reject) => {
...
...
const teams = await coreApiObject.getTeams(currProject.id)
.catch(err => { reject(err) return })
...
...
})
}
In this code I am assuming, if there is a problem with promise call, foo() is going to return reject.
async functions always return a promise, so you don't need to explicitly create one yourself. Any non-promise value returned from an async function is implicitly wrapped in a promise.
Inside the foo function, you just need to await the call coreApiObject.getTeams(...) and to catch and handle any error, use the try-catch block.
Your code can be simplified as shown below:
const foo = async() => {
try {
const teams = await coreApiObject.getTeams(currProject.id);
return teams;
} catch (e) {
// handle error
}
}
If you want to the calling code to handle the error, then you can use one of the following options:
Remove the try-catch block and just return the result of coreApiObject.getTeams(...).
const foo = async() => {
return coreApiObject.getTeams(currProject.id);
}
Removing the try-catch block and just returning the call to coreApiObject.getTeams(...) will allow the calling code to handle the error because the promise returned by the foo function will get resolved to the promise returned by coreApiObject.getTeams(...); this means that the fate of the promise returned by the foo function will depend on whatever happens to the promise returned by coreApiObject.getTeams(...).
If the promise returned by coreApiObject.getTeams(...) is rejected, promise returned by the foo function will also be rejected and hence the calling code will have a change to catch the promise rejection and handle it.
Throw the error from the catch block.
const foo = async() => {
try {
const teams = await coreApiObject.getTeams(currProject.id);
return teams;
} catch (error) {
// throw the error
throw error;
}
}
Other option is to throw the error from the catch block to make sure that the promise returned by the async function is rejected.
If you don't throw the error or return a promise or a thenable that is rejected, returning any other value from the catch block will fulfil the promise returned by the async function with whatever value is returned inside the catch block.

Testing console.log in catch block

I have the following code:
loggerManager.js:
export default log(message) {
try {
axios.post(...).catch(error) { console.log(error); }
}catch(error) {
console.log(error);
}
}
loggerManager.test.js:
test('', () => {
jest.spyOn(global.console, 'log');
jest.mock('axios');
axios.post = jest.fn(() => Promise.reject('fail'));
log('message');
expect(console.log).toBeCalledWith('fail'); // The result said it has not been called even once
});
Where am I going wrong?
Two issues:
A rejection handler converts rejection into fulfillment if it doesn't throw or return a promise that is rejected
try/catch doesn't catch promise rejections except when the promise is consumed via await within the try block
So assuming the normal case, if your axios.post's promise rejects, the rejection handler runs but the catch block does not.
In this code:
export default log(message) {
try {
axios.post(...).catch(error) { console.log(error); }
}catch(error) {
console.log(error);
}
}
Execution will only go into the catch block at the end if:
axios is an undeclared identifier; or
axios doesn't have a post property; or
axios.post isn't a function; or
axios.post throws when called; or
axios.post doesn't return an object with a catch property; or
The catch property of the object axios.post returns isn't a function; or
The catch method of the object axios.post returns throws when called
It will not be entered if axios.post returns a promise that is rejected.
You may have wanted this:
export default async log(message) {
// −−−−−−−−−−−−^^^^^
try {
await axios.post(...);
// −^^^^^
}catch(error) {
console.log(error);
}
}
That way, the catch block will be entered if there was a problem calling axios.post or if axios.post returns a promise that is rejected.

Using then() on a failed promise?

I have a store method...
async store() {
try {
return await axios.post('/upload', data);
} catch (error) {
}
},
Called by:
store().then(()=>{ console.log('ok'); }, ()=>{ console.log('not ok'); });
But when the store method fails and an error is caught, the first method in then is always called, how can I get the failed not ok method to be called?
You need to throw the error caught in the catch block of the store function
async store() {
try {
return await axios.post('/upload', data);
} catch (error) {
throw error;
}
}
You could also skip catching the error in the store function and simply catch it when store function is called. To do this, you just need to return the result of axios.post(...).
async store() {
return axios.post('/upload', data);
}
(Note that, without the try-catch block, you don't need an await before axios.post(...) because the promise returned by the store function will be resolved to the promise returned by axios.post(...). This means that if the promise returned by axios.post(...) is fulfilled, promise returned by the store function will also fulfil with the same fulfilment value with which the promise returned by axios.post(...) fulfilled.)
It is uncommon to pass second argument to then function. Instead, you should chain a .catch() block to catch the error.
store()
.then(() => console.log('ok'))
.catch(() => console.log('not ok'));

Handle exceptions within a returned promise

I know this is not the most beautiful code, but due to legacy issues, I need to stick to this workflow.
The problem is that I am not able to bubble up any exceptions that might occur in the heart of the returned promise.
The code is designed that both the reject and resolve return valid data. So, if you change the const CONDITION to 0.4, we will be getting a rejection. If the value of const CONDITION stays at 0.6, we will be getting a resolution. This works so far.
However, in cases where we have structural failures, such as in the example below where we try to pass a wrong variable name into the rejection:
let reasoxxxx = '__FAILED__';
reject({error: reason, data: output});
I am not able to invoke a throw to bubble up the error. For that reason, I am getting the usual ugly message and I cannot bubble up a proper exception:
Exchange request was rejected due to error(s).
(node:224) UnhandledPromiseRejectionWarning: ReferenceError: reason is not defined
(node:224) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:224) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Any ideas? The code snipped should work.
function fakeFetch() {
// Promisify the request.
return new Promise((resolve, reject) => {
// Emulate an asynchroneous fetch.
setTimeout(() => {
let result = 0.4; // Change to 0.4 to trigger a failed fetch.
if (result < 0.5) {;
reject('__FAIL__');
} else {
resolve({name: 'apple', price: '1234.12', time: 1549926859970});
}
}, 2000);
});
}
async function sendExchangeRequest(id, pair, symbols, callback)
{
let err, result
await fakeFetch().then((output) => { result = output }).catch((error) => {err = error})
if(err){
result = 'None'
}else{
err = 'None'
}
callback(err, result)
}
async function fetchExchangeData(id, pair, symbols) {
// Promisify the request.
try {
return new Promise((resolve, reject) => {
try {
// Send the request.
sendExchangeRequest(id, pair, symbols, ((err, output) => {
try{
if(err){
// Soft Failure
console.log('Exchange request was rejected due to error(s).');
reject({error: err, data: output});
}else{
// Success
console.log('Exchange request was successful.');
resolve({error: err, data: output});
}
} catch(error) {
throw error;
}
}));
} catch(error) {
console.log('---\n', error, '\n---');
throw error;
}
});
} catch(error) {
// Bubble up the error?
console.log('+++\n', error, '\n+++');
throw error;
}
}
(async () => {
await fetchExchangeData('myid', 'MYPAIR', 'mySymbol')
.then((result) => console.log(result))
.catch((failure) => console.log(failure))
})();
--- EDIT (01) ---
I have updated my example snipped to include a fake API call. I hope this makes my question a bit more clear.
I think you're not understanding the concept of async functions. Your first try/catch in fetchExchangeData do essentially nothing, and there is nothing async in it. The try/catch inside the initial promise, is also almost useless, as I'm sure most/all issues with sendExchangeRequest will likely be dealt with the error handler function (err). As for the try/catch blocks, you shouldn't throw errors inside the promise, you should instead reject the error (Which will bubble it up). Only try/catch if you're in an async function, and NOT using callbacks.
function fetchExchangeData(id, pair, symbols) {
// Promisify the request.
return new Promise((resolve, reject) => {
try {
// Send the request.
sendExchangeRequest(id, pair, symbols, ((err, output) => {
try{
if(err){
// Soft Failure
console.log('Exchange request was rejected due to error(s).');
let reason = '__FAILED__';
reject({error: reason, data: output});
}else{
// Success
console.log('Exchange request was successful.');
resolve({error: '__NONE__', data: output});
}
} catch(error) {
reject(error);
}
}));
} catch(error) {
console.log('---\n', error, '\n---');
reject(error);
}
});
}

Categories