Javascript fetch, catch runs forever - javascript

What happens: If I use fetch..catch and calls another function. In that next function if anything crashes. It will be caught in last catch. This will go on so if the next function crashes it will still be caught in the fetch..catch
What I want: When calling myExternalFunction() I want to 'disconnect' from the try..catch that fetch throws.
fetch('mystuff.url')
.then((data)=>{
myExternalFunction();
})
.catch((e)=>{
// all future errors will come here
})
myExternalFunction(){
// This error will be caught by fetch..catch
// we don't want that
crash();
}
Fiddler example to try it

You don't want to chain your catch to the then then, but keep them at the same level:
fetch(...).then(successCallback, failCallback)
Or:
const p = fetch(...);
p.then(successCallback);
p.catch(failCallback);
const p = Promise.resolve('foo');
p.then(() => { throw new Error('noooooo') });
p.catch(() => console.error('caught'));
The difference is that fetch().then().catch() will catch any error produced by either the fetch promise or the then promise; while the above two methods apply the failCallback only to the fetch promise.

When calling myExternalFunction() I want to 'disconnect' from the
try..catch that fetch throws.
Catch the exception of crash in myExternalFunction itself.
fetch('mystuff.url')
.then((data)=>{
myExternalFunction();
})
.catch((e)=>{
// all future errors will come here
})
function myExternalFunction(){
try
{
crash();
}
catch(e)
{
//do nothing
}
}
Or (if modifying external function is not possible) catch the same in then
fetch('mystuff.url')
.then((data)=>{
try
{
myExternalFunction();
}
catch(e)
{
//do nothing
}
})
.catch((e)=>{
// all future errors will come here
})
function myExternalFunction(){
crash();
}

If we don't want to wrap the 'external function' in try..catch (then we need to continue to wrap next call as well and so on. This issue can be noted when e.g. using react with redux thunk. How a fetch..catch captures errors happening somewhere else.
To completly break we need something else as setTimeout. Must be a better way for this.
fetch('mystuff.url')
.then((data)=>{
// this will break out so 'external function' doesn't get caught in catch.
setTimeout(myExternalFunction,1);
})
.catch((e)=>{
// only errors from the fetch
})
function myExternalFunction(){
crash(); // we are happy, it crashes without involving fetch
}

If you want to use catch with fetch I propose to use this solution.
fetch("http://httpstat.us/500")
.then(function(response) {
if (!response.ok) {
throw Error(response.status);
}
return response;
}).then(function(response) {
alert("ok");
}).catch(function(error) {
alert(error);
});

Related

try...catch if a function throws error NodeJS

I'm trying to handle a function if it throws an error: create.js
function Apple() {
createDB() //function that saves into db
}
createDB.js
function createDB() {
const Info = new collection(data)
Info.save()
}
Suppose createDB function throws an error when required field in the db is not present. I want to handle such errors.
I tried:
function Apple() {
try{
createDB()//function that saves into db //if throws error go to catch
block
} catch{
function that handles error
}
}
and I also tried:
function createDB() {
return new Promise((resolve, reject) => {
if some condition met{
const Info = new collection(data)
Info.save()
}else{
reject(error)
}
})
}
But it still doesn't goes to the catch block. I'm relatively new to the topic so any suggestions will be really helpful. Basically I want to handle the errors if a function throws error, and it should go to catch block.
You are actually not following the correct syntax. Check out the sampe one:
try {
nonExistentFunction();
} catch (error) {
console.error(error);
// expected output: ReferenceError: nonExistentFunction is not defined
// Note - error messages will vary depending on browser
}
Your updated code with try-catch should follow the above syntax:
function Apple() {
try{
createDB()//function that saves into db //if throws error go to catch
block
} catch (error) {
function that handles error
// here you should log errors or use the logging lib
}
}
Also, if you are using promises, you can follow this approach:
function createDB() {
return new Promise((resolve, reject) => {
if (condition) {
const Info = new collection(data);
Info.save().then(data =>{ resolve(data)})
.catch(e => {console.error(e)}) // handle this promise also
}
else {
reject(error);
}
})
}
Also, you need to understand when to use try-catch block and when to use promises. The try, catch blocks are used to handle exceptions (a type of an error) when the code is synchronous. You should use Promises only for asynchronous functions and nothing else.
Use this sample piece of code
Within try block we write our code which we want to execute
If any error occur controller goes to catch block
In catch block we also receive error
try {
//Here write your code which you want to execute
return true
} catch (error) {
//if there is an any error controller will come into this block and show error
console.error(error);
return false
}

Throw an error to a catch handler and ignore then functions?

I have a helper function:
function httpRequestHelper(body) {
return fetch(`${host}:${port}`, {
method: 'post',
body: JSON.stringify(body)
})
.then(function (response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(response) {
if (response.type === 'error') {
throw Error(response);
}
return response;
})
.catch(function(error) {
return error;
});
}
that I wrote to keep functions for various commands short. These functions just specify the body to be sent and what part of the response is relevant to the consumer:
function hasActiveProject() {
return httpRequestHelper({ type: 'request', cmd: 'has_active_project' })
.then(function (response) {
return response.payload.value;
})
}
I execute the various commands like this:
try {
let hasActiveProjectResponse = await otii.hasActiveProject()
console.log(hasActiveProjectResponse);
} catch (error) {
console.log(error);
}
Now the problem is that in the catch function I would expect to get the error message thrown, but instead I get error messages like:
TypeError: Cannot read property 'value' of undefined
This is because hasActiveProject() tries to extract the relevant response even when there was an error and that causes a different error that is returned to my catch (error) handler.
How can I rewrite this so that
hasActiveProject() remains thin
The catch handler receives the original error
Are you sure you have an error? and response.payload is not undefined? because in this test fiddle you can see that its working as you want it to, the try catches the errors thrown inside the .then function, and doesn't continue.
https://jsfiddle.net/8qe1sxg4/6/
It looks like response.type is valid, so you don't have any errors thrown, can you confirm the results you get?
UPDATE
After some more researching, the catch function doesn't bubble to the next catch, it considered as if you already handled the error and continue as usual (with the resolved value from the catch).
But you can simply reject again inside the .catch(), so this way your error will bubble to the try/catch:
in httpRequestHelper():
.catch(function(error) {
return Promise.reject(error)
//return error;
});
This will send your error to the next catch, see fiddle for example:
https://jsfiddle.net/dcuo46qk/3/

Uncaught (in promise)

I know the problem is usual. I'm using es6 promises, and I have multiple layers.
On runtime, when I don't catch a promise, I have Uncaught (in promise) in my console. But the fact is that I do catch it lower in my code.
Fast simplified example :
LoginApi.js
var loginDaoCall = loginDao.login(username, password);
loginDaoCall
.then(function (res) {
store.dispatch(loginSuccess());
log.log("[loginApi.login] END");
})
.catch(function (err) {
store.dispatch(loginFail());
errorUtils.dispatchErrorWithTimeout(errorLogin);
log.log(err);
});
return loginDaoCall;
loginContainer.js
loginApi.login(user, password).then(() => {
// Change here instead of in render so the user can go back to login page
this.props.history.push(baseUrlRouter + "test");
}); // <- Error here cause I don't CATCH the promise, but I do catch it in my loginapi.js
I know that I could catch doing nothing, but eh. I could also do the history push thing in my API layer, but it is not its responsibility.
How can I avoid the error in my console? Is there a way? I'm even thinking about leaving it like this.
Your problem is that you were returning the rejected loginDaoCall, not the promise where the error was already handled. loginApi.login(user, password) did indeed return a rejected promise, and even while that was handled in another branch, the promise returned by the further .then() does also get rejected and was not handled.
You might want to do something like
// LoginApi.js
return loginDao.login(username, password).then(function (res) {
store.dispatch(loginSuccess());
log.log("[loginApi.login] END");
return true;
}, function (err) {
store.dispatch(loginFail());
errorUtils.dispatchErrorWithTimeout(errorLogin);
log.log(err);
return false;
}); // never supposed to reject
// loginContainer.js
loginApi.login(user, password).then(success => {
if (success) {
// Change here instead of in render so the user can go back to login page
this.props.history.push(baseUrlRouter + "test");
}
});
It sounds like you have an error in your catch block. When the error is thrown there is no 2nd catch block to catch the error in the 1st catch block.
To fix it ...
.then(function (res) {
// some code that throws an error
})
.catch(function (err) {
// some code that throws an error
})
.catch(function (err) {
// This will fix your error since you are now handling the error thrown by your first catch block
console.log(err.message)
});

Rethrowing error in promise catch

I found the following code in a tutorial:
promise.then(function(result){
//some code
}).catch(function(error) {
throw(error);
});
I'm a bit confused: does the catch call accomplish anything? It seems to me that it doesn't have any effect, since it simply throws the same error that was caught. I base this on how a regular try/catch works.
There is no point to a naked catch and throw as you show. It does not do anything useful except add code and slow execution. So, if you're going to .catch() and rethrow, there should be something you want to do in the .catch(), otherwise you should just remove the .catch() entirely.
The usual point for that general structure is when you want to execute something in the .catch() such as log the error or clean up some state (like close files), but you want the promise chain to continue as rejected.
promise.then(function(result){
//some code
}).catch(function(error) {
// log and rethrow
console.log(error);
throw error;
});
In a tutorial, it may be there just to show people where they can catch errors or to teach the concept of handling the error, then rethrowing it.
Some of the useful reasons for catching and rethrowing are as follows:
You want to log the error, but keep the promise chain as rejected.
You want to turn the error into some other error (often for easier error processing at the end of the chain). In this case, you would rethrow a different error.
You want to do a bunch of processing before the promise chain continues (such as close/free resources) but you want the promise chain to stay rejected.
You want a spot to place a breakpoint for the debugger at this point in the promise chain if there's a failure.
You want to handle a specific error or set of errors, but rethrow others so that they propagate back to the caller.
But, a plain catch and rethrow of the same error with no other code in the catch handler doesn't do anything useful for normal running of the code.
Both .then() and .catch() methods return Promises, and if you throw an Exception in either handler, the returned promise is rejected and the Exception will be caught in the next reject handler.
In the following code, we throw an exception in the first .catch(), which is caught in the second .catch() :
new Promise((resolve, reject) => {
console.log('Initial');
resolve();
})
.then(() => {
throw new Error('Something failed');
console.log('Do this'); // Never reached
})
.catch(() => {
console.log('Something failed');
throw new Error('Something failed again');
})
.catch((error) => {
console.log('Final error : ', error.message);
});
The second .catch() returns a Promised that is fulfilled, the .then() handler can be called :
new Promise((resolve, reject) => {
console.log('Initial');
resolve();
})
.then(() => {
throw new Error('Something failed');
console.log('Do this'); // Never reached
})
.catch(() => {
console.log('Something failed');
throw new Error('Something failed again');
})
.catch((error) => {
console.log('Final error : ', error.message);
})
.then(() => {
console.log('Show this message whatever happened before');
});
Useful reference : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch
Hope this helps!
There is no important difference if you leave out the catch method call completely.
The only thing it adds is an extra microtask, which in practice means you'll notice the rejection of the promise later than is the case for a promise that fails without the catch clause.
The next snippet demonstrates this:
var p;
// Case 1: with catch
p = Promise.reject('my error 1')
.catch(function(error) {
throw(error);
});
p.catch( error => console.log(error) );
// Case 2: without catch
p = Promise.reject('my error 2');
p.catch( error => console.log(error) );
Note how the second rejection is reported before the first. That is about the only difference.
So it sounds like your question is, "In the promise chain, what does the .catch() method do?"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw
The throw statement "will stop (the statements after throw won't be executed), and control will be passed to the first catch block in the call stack. If no catch block exists among caller functions, the program will terminate."
In the promise chain, the .then() method will return some type of data chunk. This return of the chunk will complete the promise. The successful return of the data completes the promise. You can think of the .catch() method in the same way. .catch() however will handle unsuccessful data retrieves. The throw statement completes the promise. Occasionally, you will see developers use .catch((err) => {console.log(err))} which would also complete the promise chain.
You actually don't need to re throw it, just leave the Promise.catch empty otherwise it will consider as un handle the reject and then wrap the code in a try catch and it will catch the error automatically which is passing down.
try{
promise.then(function(result){
//some code
}).catch(function(error) {
//no need for re throwing or any coding. but leave this as this otherwise it will consider as un handled
});
}catch(e){
console.log(e);
//error can handle in here
}
In the promise chain, it is better to use .catch
ex in function f2: .then(...).catch(e => reject(e));
test1 - with try catch
test2 - without try or .catch
test3 - with .catch
function f1() {
return new Promise((resolve, reject) => {
throw new Error('test');
});
}
function f2() {
return new Promise((resolve, reject) => {
f1().then(value => {
console.log('f1 ok ???');
}).catch(e => reject(e));
});
}
function test1() {
console.log('test1 - with try catch - look in F12');
try {
f2().then(() => { // Uncaught (in promise) Error: test
console.log('???'); });
} catch (e) {
console.log('this error dont catched');
}
}
function test2() {
console.log('test2 - without try or .catch - look in F12');
f2(); // Uncaught (in promise) Error: test
}
function test3() {
console.log('test3 - with .catch');
f2().then(value => {
console.log('??');
}).catch(e => {
console.log(' now its ok, error ', e);
})
}
setTimeout(() => { test1();
setTimeout(() => { test2();
setTimeout(() => { test3();
}, 100);
}, 100);
}, 100);

correct way to break promise chain on first rejection [duplicate]

I am still fairly new to promises and am using bluebird currently, however I have a scenario where I am not quite sure how to best deal with it.
So for example I have a promise chain within an express app like so:
repository.Query(getAccountByIdQuery)
.catch(function(error){
res.status(404).send({ error: "No account found with this Id" });
})
.then(convertDocumentToModel)
.then(verifyOldPassword)
.catch(function(error) {
res.status(406).send({ OldPassword: error });
})
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
So the behaviour I am after is:
Goes to get account by Id
If there is a rejection at this point, bomb out and return an error
If there is no error convert the document returned to a model
Verify the password with the database document
If the passwords dont match then bomb out and return a different error
If there is no error change the passwords
Then return success
If anything else went wrong, return a 500
So currently catches do not seem to stop the chaining, and that makes sense, so I am wondering if there is a way for me to somehow force the chain to stop at a certain point based upon the errors, or if there is a better way to structure this to get some form of branching behaviour, as there is a case of if X do Y else Z.
Any help would be great.
This behavior is exactly like a synchronous throw:
try{
throw new Error();
} catch(e){
// handle
}
// this code will run, since you recovered from the error!
That's half of the point of .catch - to be able to recover from errors. It might be desirable to rethrow to signal the state is still an error:
try{
throw new Error();
} catch(e){
// handle
throw e; // or a wrapper over e so we know it wasn't handled
}
// this code will not run
However, this alone won't work in your case since the error be caught by a later handler. The real issue here is that generalized "HANDLE ANYTHING" error handlers are a bad practice in general and are extremely frowned upon in other programming languages and ecosystems. For this reason Bluebird offers typed and predicate catches.
The added advantage is that your business logic does not (and shouldn't) have to be aware of the request/response cycle at all. It is not the query's responsibility to decide which HTTP status and error the client gets and later as your app grows you might want to separate the business logic (how to query your DB and how to process your data) from what you send to the client (what http status code, what text and what response).
Here is how I'd write your code.
First, I'd get .Query to throw a NoSuchAccountError, I'd subclass it from Promise.OperationalError which Bluebird already provides. If you're unsure how to subclass an error let me know.
I'd additionally subclass it for AuthenticationError and then do something like:
function changePassword(queryDataEtc){
return repository.Query(getAccountByIdQuery)
.then(convertDocumentToModel)
.then(verifyOldPassword)
.then(changePassword);
}
As you can see - it's very clean and you can read the text like an instruction manual of what happens in the process. It is also separated from the request/response.
Now, I'd call it from the route handler as such:
changePassword(params)
.catch(NoSuchAccountError, function(e){
res.status(404).send({ error: "No account found with this Id" });
}).catch(AuthenticationError, function(e){
res.status(406).send({ OldPassword: error });
}).error(function(e){ // catches any remaining operational errors
res.status(500).send({ error: "Unable to change password" });
}).catch(function(e){
res.status(500).send({ error: "Unknown internal server error" });
});
This way, the logic is all in one place and the decision of how to handle errors to the client is all in one place and they don't clutter eachother.
.catch works like the try-catch statement, which means you only need one catch at the end:
repository.Query(getAccountByIdQuery)
.then(convertDocumentToModel)
.then(verifyOldPassword)
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error) {
if (/*see if error is not found error*/) {
res.status(404).send({ error: "No account found with this Id" });
} else if (/*see if error is verification error*/) {
res.status(406).send({ OldPassword: error });
} else {
console.log(error);
res.status(500).send({ error: "Unable to change password" });
}
});
I am wondering if there is a way for me to somehow force the chain to stop at a certain point based upon the errors
No. You cannot really "end" a chain, unless you throw an exception that bubbles until its end. See Benjamin Gruenbaum's answer for how to do that.
A derivation of his pattern would be not to distinguish error types, but use errors that have statusCode and body fields which can be sent from a single, generic .catch handler. Depending on your application structure, his solution might be cleaner though.
or if there is a better way to structure this to get some form of branching behaviour
Yes, you can do branching with promises. However, this means to leave the chain and "go back" to nesting - just like you'd do in an nested if-else or try-catch statement:
repository.Query(getAccountByIdQuery)
.then(function(account) {
return convertDocumentToModel(account)
.then(verifyOldPassword)
.then(function(verification) {
return changePassword(verification)
.then(function() {
res.status(200).send();
})
}, function(verificationError) {
res.status(406).send({ OldPassword: error });
})
}, function(accountError){
res.status(404).send({ error: "No account found with this Id" });
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
I have been doing this way:
You leave your catch in the end. And just throw an error when it happens midway your chain.
repository.Query(getAccountByIdQuery)
.then((resultOfQuery) => convertDocumentToModel(resultOfQuery)) //inside convertDocumentToModel() you check for empty and then throw new Error('no_account')
.then((model) => verifyOldPassword(model)) //inside convertDocumentToModel() you check for empty and then throw new Error('no_account')
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch((error) => {
if (error.name === 'no_account'){
res.status(404).send({ error: "No account found with this Id" });
} else if (error.name === 'wrong_old_password'){
res.status(406).send({ OldPassword: error });
} else {
res.status(500).send({ error: "Unable to change password" });
}
});
Your other functions would probably look something like this:
function convertDocumentToModel(resultOfQuery) {
if (!resultOfQuery){
throw new Error('no_account');
} else {
return new Promise(function(resolve) {
//do stuff then resolve
resolve(model);
}
}
Probably a little late to the party, but it is possible to nest .catch as shown here:
Mozilla Developer Network - Using Promises
Edit: I submitted this because it provides the asked functionality in general. However it doesn't in this particular case. Because as explained in detail by others already, .catch is supposed to recover the error. You can't, for example, send a response to the client in multiple .catch callbacks because a .catch with no explicit return resolves it with undefined in that case, causing proceeding .then to trigger even though your chain is not really resolved, potentially causing a following .catch to trigger and sending another response to the client, causing an error and likely throwing an UnhandledPromiseRejection your way. I hope this convoluted sentence made some sense to you.
Instead of .then().catch()... you can do .then(resolveFunc, rejectFunc). This promise chain would be better if you handled things along the way. Here is how I would rewrite it:
repository.Query(getAccountByIdQuery)
.then(
convertDocumentToModel,
() => {
res.status(404).send({ error: "No account found with this Id" });
return Promise.reject(null)
}
)
.then(
verifyOldPassword,
() => Promise.reject(null)
)
.then(
changePassword,
(error) => {
if (error != null) {
res.status(406).send({ OldPassword: error });
}
return Promise.Promise.reject(null);
}
)
.then(
_ => res.status(200).send(),
error => {
if (error != null) {
console.error(error);
res.status(500).send({ error: "Unable to change password" });
}
}
);
Note: The if (error != null) is a bit of a hack to interact with the most recent error.
I think Benjamin Gruenbaum's answer above is the best solution for a complex logic sequence, but here is my alternative for simpler situations. I just use an errorEncountered flag along with return Promise.reject() to skip any subsequent then or catch statements. So it would look like this:
let errorEncountered = false;
someCall({
/* do stuff */
})
.catch({
/* handle error from someCall*/
errorEncountered = true;
return Promise.reject();
})
.then({
/* do other stuff */
/* this is skipped if the preceding catch was triggered, due to Promise.reject */
})
.catch({
if (errorEncountered) {
return;
}
/* handle error from preceding then, if it was executed */
/* if the preceding catch was executed, this is skipped due to the errorEncountered flag */
});
If you have more than two then/catch pairs, you should probably use Benjamin Gruenbaum's solution. But this works for a simple set-up.
Note that the final catch only has return; rather than return Promise.reject();, because there's no subsequent then that we need to skip, and it would count as an unhandled Promise rejection, which Node doesn't like. As is written above, the final catch will return a peacefully resolved Promise.
I wanted to preserve the branching behaviour that Bergi's answer had, yet still provide the clean code structure of unnested .then()'s
If you can handle some ugliness in the machinery that makes this code work, the result is a clean code structure similar to non-nested chained .then()'s
One nice part of structuring a chain like this, is that you can handle all the potential results in one place by chainRequests(...).then(handleAllPotentialResults) this might be nice if you need to hide the request chain behind some standardised interface.
const log = console.log;
const chainRequest = (stepFunction, step) => (response) => {
if (response.status === 200) {
return stepFunction(response, step);
}
else {
log(`Failure at step: ${step}`);
return response;
}
};
const chainRequests = (initialRequest, ...steps) => {
const recurs = (step) => (response) => {
const incStep = step + 1;
const nextStep = steps.shift();
return nextStep ? nextStep(response, step).then(chainRequest(recurs(incStep), incStep)) : response;
};
return initialRequest().then(recurs(0));
};
// Usage
async function workingExample() {
return await chainRequests(
() => fetch('https://jsonplaceholder.typicode.com/users'),
(resp, step) => { log(`step: ${step}`, resp); return fetch('https://jsonplaceholder.typicode.com/posts/'); },
(resp, step) => { log(`step: ${step}`, resp); return fetch('https://jsonplaceholder.typicode.com/posts/3'); }
);
}
async function failureExample() {
return await chainRequests(
() => fetch('https://jsonplaceholder.typicode.com/users'),
(resp, step) => { log(`step: ${step}`, resp); return fetch('https://jsonplaceholder.typicode.com/posts/fail'); },
(resp, step) => { log(`step: ${step}`, resp); return fetch('https://jsonplaceholder.typicode.com/posts/3'); }
);
}
console.log(await workingExample());
console.log(await failureExample());
The idea is there, but the interface exposed could probably use some tweaking.
Seeing as this implementation used curried arrow functions, the above could potentially be implemented with more direct async/await code

Categories

Resources