ReactJS and Promise: How to call catch inside then? - javascript

So, I have got an action creator (that returns a function - I use redux-thunk). Inside the function the creator returns, I call a dispatch method and chain the then and catch methods.
Here how it looks like:
export function actionCreator(someData) {
(dispath, getState) => {
return dispatch(someAction)
.then(resp => {
//do something
// GO TO CATCH
})
.catch(err => {
return err;
})
}
}
You see the GO TO CATCH comment over there? So, how can I go to the catch block from there?
Thank you!

If you want to jump from the body of a .then() to the following .catch(), the easiest way is to throw an error:
throw new Error('I meant to blow up here.');
The error you throw is what will be passed to the body of the .catch() (the err variable, in your case).
Please note that your example already looks suspect though: your catch block is catching an error and then returning it as if the error was a regular value, which means any upstream promise-based handling will assume the dispatch was successful. Are you sure that's what you want?

Related

With Javascript Promises, are there best practices regarding the use of "error" versus catch clauses?

In learning to write in JavaScript with Promises, I'm encountering two different ways of dealing with errors. One is to use a catch, as in this example:
axios.post('/someapi', {
somedata1: 'foo'
})
.then((result) => {
console.log(result);
})
.catch((exception) => {
console.log(exception);
});
The other is to have a clause in the then for the rejected case:
axios.post('/someapi', {
somedata1: 'foo',
})
.then((response) => {
console.log(response);
}, (error) => {
console.log(error);
});
Some authors seem to use one approach, other authors use the other, and it's not clear to me why. Are there situations in which it's necessary or desirable to use one or the other?
(The example above uses axios, but that's just for the purposes of providing a code example. This question is not about axios.)
With Javascript Promises, are there best practices regarding the use of “error” versus catch clauses?
There is no universal "best practice" for that question because it depends upon what specific behavior you want your code to have. As others have mentioned, you get a different behavior in a few ways.
Some authors seem to use one approach, other authors use the other, and it's not clear to me why. Are there situations in which it's necessary or desirable to use one or the other?
Yes, there are situations to use one or the other. They provide potentially different behaviors. Only if you're 200% sure that your successHandler in .then(successHandler) can never throw or return a rejected promise, would there be no meaningful difference.
As a summary:
When using p.then(successHandler).catch(errorHandler), errorHandler will get errors that occur either from a rejected p or from an error or rejection from the successHandler.
When using p.then(successHandler, errorHandler), errorHandler will be called from a rejection of p and will NOT get called from an error or rejection from the successHandler.
Different behaviors that are useful for different circumstances.
In this .catch() example below, the .catch() will catch an error that occurs (either accidentally from a coding error, a thrown exception or when returning some other promise that rejects).
Promise.resolve("hello").then(greeting => {
console.log("throwing error");
throw new Error("My .then() handler had an error");
}).catch(err => {
// will get here
console.log("Caught error in .catch()\nError was: ", err.message);
});
But, when using the second argument to .then(), that error from the .then() handler will not be caught:
Promise.resolve("hello").then(greeting => {
console.log("throwing error");
throw new Error("My .then() handler had an error");
}, err => {
// won't get here
console.log("Caught error in .catch()\nError was: ", err.message);
});
So, sometimes you want an error that might occur in the .then() handler to hit this immediate error handler and sometimes you don't want it to hit that error handler because you want that error handler to only process errors from the original promise and you have some other catch handler later in the promise chain that will deal with this error.
Recommendation
In general, I would advise that you start out with the .catch() handler because it catches more errors and does not require that there be some other .catch() handler elsewhere in the promise chain in order to be safe. Then, you switch to the .then(successHandler, errorHandler) form if you explicitly don't want this errorHandlerto be called if there's another error in the successHandler AND you have somewhere else in the promise chain where an error in the successHandler would get caught or handled.
Both the syntaxes work out of the box. But the first one has an advantage that the Catch block is able to catch an error thrown by the Promise Rejection as well as an error thrown by then block.
Here is the Example you can try in Node and you will have a better idea about it.
function x () {
return new Promise((resolve, reject) => {
return resolve('Done...');
});
}
x()
.then(response => {
console.log('RESPONSE---', response)
throw 'Oops...Error occurred...';
})
.catch(error => console.log('ERROR---', error));
x()
.then(
response => {
console.log('RESPONSE---', response)
throw 'Oops...Error occurred...';
},
error => console.log('ERROR---', error)
);

What is the difference between using Promise.catch() and wrapping a Promise in try...catch?

I was sitting in listening to a Javascript class today and they were covering something I hadn't seen before and which I don't fully understand. I will try to reproduce as best I can from memory
Instead of using the catch of a Promise to handle errors, which I'm used to, the teacher used try...catch wrapped around the Promise and its thens. When I asked him why he did this, he said it was to catch the error 'synchronously'. That is, instead of the following format (I'm using pseudocode), which I'm used to
someLibrary.someFunctionThatReturnsAPromise
.then(() => something)
.then(() => somethingElse)
.catch(err => reportError)
he did it thus
try {
someLibrary.someFunctionThatReturnsAPromise
.then(() => something)
.then(() => somethingElse)
}
catch(err) {
reportError
}
What would be the difference between these two ways of catching the error?
How would wrapping a Promise, which is asynchronous, report errors in a synchronous fashion?
Thanks for any insights!
The try-catch won't catch asynchronous errors around a <somePromise>.then since as you've noticed, the block will exit before the promise has finished/potentially thrown.
However, if you are using async/await then the try-catch will catch since the block will wait for the await:
async function foobar() {
try {
await doSomePromise();
} catch (e) {
console.log(e);
}
}
The try/catch version will only catch the error if the error is thrown when the initial (synchronous) code is running - it will not catch errors that are thrown inside any of the .thens:
try {
Promise.resolve()
.then(() => {
throw new Error()
});
} catch(e) {
console.log('caught');
}
So, the only way an error will be caught with try/catch in your code is if someLibrary.someFunctionThatReturnsAPromise throws synchronously. On the other hand, the .then/.catch version will catch any error (and is almost certainly preferable).
catch after then (first example)
it is a short way to to handle only error from your promise. It is the same as
.then(null, (err) => reportError)
as then takes two parameters: for fulfilled and rejected state of the promise.
try catch block (second example)
in short - is is a common way to handle your code block. if you what from your code not only failed but do something after it. Try/catch is working only in sync mode, that is why if you work with async code, you should wrap it, for example in async/await way.
Actually you can also you use 3 statement after catch - finally, but it depends )

what is dot for in front of .catch? (firebase auth, react native)

I am very new to react native with somewhat of a background in C(EE courses) and is just trying to understand the concepts. I'm currently folloing a react native course on Udemy.
I am trying to create a login form using firebase + react native.
Here I would like to notify the user if an error occurs with their login.
I have two sets of code below in which I attempt to do the same thing, one of them works and the other one doesn't. I would like to understand why the first one works, and why the second one doesn't
This does work:
firebase.auth().createUserWithEmailAndPassword(email, password)
.catch((error) => {
this.setState({ error: error.message, loading: false });
});
Why do I need to put error on the left of the arrow function? From my understanding, whatever is on the left side of the arrow function can be seen as the "input", and the rightside is the system/output?
This doesn't work:
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(this.createFailure.bind(this))
createFailure() {
.catch((error) => {
this.setState({ error: error.message, loading: false });
});
}
This one gives me a parse error for the '.' in front of catch.
I don't think I quite understand how .catch works but I was only able to find catch() on mozilla without the '.'
it seems that I lack some fundamental understanding of how certain elements work, are there any recommended Youtube series that explains these building blocks? I find documentations often have too many corner cases which makes everything quite confusing.
createUserWithEmailAndPassword returns a promise object. That object has a catch method, which you use to hook up a handler for when the promise rejects. So the . is just like the . in, say, $("#foo").html(): It's accessing the method on the object returned by the function.
Why do I need to put error on the left of the arrow function? From my understanding, whatever is on the left side of the arrow function can be seen as the "input", and the rightside is the system/output?
Pretty much, yes. The arrow function is called if the promise rejects. When it gets called, it receives the error as input, and then does something with that error.
This asynchronous code using promises:
doSomething()
.then(data => {
// ...do something with data...
})
.catch(error => {
// ...do something with error...
});
is the same, logically, as this synchronous code:
try {
const data = doSomething();
// ...do something with data
} catch (error) {
// ...do something with error
}
and in fact, if you use an async function, you can write the asynchronous version using promises almost exactly like that:
// (within an `async` function)
try {
const data = await doSomething();
// Note -----^^^^^^
// ...do something with data
} catch (error) {
// ...do something with error
}
Re your code that doesn't work, if I assume you want to call createFailure when an error occurs, you probably want this (see comments):
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(result => {
// This is the success path
this.setState({/*...from result...*/});
}
.catch(error => {
// This is the error path
this.createFailure(error);
});
or within an async function:
// (within an `async` function)
try {
const result = await firebase.auth().createUserWithEmailAndPassword(email, password);
// This is the success path
this.setState({/*...from result...*/});
} catch (error) {
// This is the error path
this.createFailure(error);
}

promise catch not working

employeeData.js
function getById(id) {
return dbPromise.one(); // using pg-promise
}
employeeService.js
function getInfoById(id) {
return employeeData.getXYZ(id); // purposefully calling a function that does not exist in the employeeData module
}
employeeApi.js // Express route function
const getInfoById = (req, res) {
employeeService.getInfoById(123)
.then(response => {
res.json(response);
})
.catch(err => {
res.json(err); // this is not being triggered
});
}
In the employeeService above I purposefully mis-typed the function name and I think it should throw an undefined error for calling a function getXYZ that does not exist in the employeeData.js. However, the catch block in employeeApi.js is not called.
Can you suggest what I might be missing here?
I think it should throw an undefined error for calling a function that does not exist
Yes, it does that. It throws an exception, it does not return a promise. As such, there is no promise object on which the then(…).catch(…) methods could be invoked.
However, the catch block is not called.
There is no catch block, it's just a method call - which doesn't happen because there's an exception. To catch it, you would need an actual try/catch block.
But that would look weird, and that's the reason why promise-returning functions should never throw. You could wrap the code with the mistake in a new Promise executor which would catch them, but the simpler choice is to use async/await syntax which guarantees to always return a promise (and reject it in case of an exception in the function body).
async function getInfoById {
return employeeData.getXYZ(123);
}

When do async methods throw and how do you catch them?

From node doc:
A handful of typically asynchronous methods in the Node.js API may
still use the throw mechanism to raise exceptions that must be handled
using try / catch. There is no comprehensive list of such methods;
please refer to the documentation of each method to determine the
appropriate error handling mechanism required.
Can someone bring example of such function which is async and still throws? How and when do you catch the exception then?
More particularly. Do they refer to such function:
try
{
obj.someAsync("param", function(data){
console.log(data);
});
}catch(e)
{
}
Now normally I know above doesn't make sense -because when the callback executes, try block could have been already exited.
But what kind of example does the excerpt from documentation refer to? If async method throws as they say it, where, when and how should I handle it? (or maybe if you show such function can you show where in its doc it says how to handle it as mentioned on the quote?)
The async methods like the one from your example usually throw for programmer errors like bad parameters and they call the callback with error for operational errors.
But there are also async functions in ES2017 (declared with async function) and those signal errors by rejecting the promise that they return - which turn into a thrown exception when you use them with await keyword.
Examples:
function x(arg, cb) {
if (!arg) throw new Error('Programmer error: bad arguments');
setTimeout(() => {
cb(new Error('Operational error: something bad happened'));
}, 2000);
}
Now when you use it you usually don't want to handle programmer errors - you want to fix them. So you don't do this:
try {
x();
} catch (err) {
// Why should I handle the case of bad invocation
// instead of fixing it?
}
And the operational errors you handle like this:
x(function (err) {
if (err) {
// handle error
} else {
// success
}
});
Now, if you have a function that doesn't take a callback but returns a promise:
function y() {
return new Promise((res, rej) => setTimeout(() => rej('error'), 2000));
}
Then you handle the error like this:
y().catch(error => {
// handle error
});
or, while using await:
try {
await y();
} catch (err) {
// handle error
}
For more info on the difference between operational errors and programmer errors see:
Best Practices for Error Handling in Node.js by Dave Pacheco
Error Handling in Node.js
For more info on the promises and async/await see the links in this answer.
afaik there are three ways a async function could "throw"; and how to catch each of these:
as any other function (aka. someone messed up): I'd not catch these cases because they should not be in my code, and catching such errors makes it harder to find and fix em.
function foo(){
//someone messed up, better fixing than catching this
return new Prooooooooooomise((resolve) => 42);
}
try {
foo();
}catch(err){
console.error(err);
}
Promises:
function foo(){ return Promise.resolve('bar') }
foo().then(value => value =========> 'error')
.catch(err => {
console.error(err);
return "fixedValue";
});
And Nodes callback syntax/pattern:
function foo(value, callback){
setTimeout(function(){
if(Math.random() < .5){
callback("I don't like to", undefined);
}else{
callback(null, value * 2);
}
}, 500);
}
foo(21, function(err, data){
if(err){
//no try..catch at all
console.error(err);
}else{
//do whatever with data
}
})
These are the most common async errors you'll come along; well, the first one is just a plain bug in an async mothod.

Categories

Resources