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)
});
Related
Then a promise calls another promise and the inner promise returns from catch the outer one processes in the .then block
I have searched here and google generally.
Tried to use a simple try.. catch. But will not work with calling a promise
assignResolver(data)
.then(function(resp) {
console.log("map then");
console.log(resp);
})
.catch(function(err) {
console.log("map catch");
console.log(err);
});
export async function assignResolver(data) {
csrf();
return api
.post("/api/task/assignResolver", data)
.then(function(res){
console.log("in api then block");
return res.data;
} )
.catch(function(err) {
console.log("in api then block");
console.log(err);
});
}
Just throw the error again, when inside the inner catch, and it'll be handled in the outer catch, and not the outer .then:
export async function assignResolver(data) {
csrf();
return api
.post("/api/task/assignResolver", data)
.then(function(res){
console.log("in api then block");
return res.data;
} )
.catch(function(err) {
console.log("in api then block");
console.log(err);
throw err;
});
}
But this is a bit strange to do - it usually makes more sense to catch in only one place. For example, if assignResolver really needs to be able to do something specific when encountering an error, and your outer caller needs to be able to do something else when encountering the error as well, having two catches can be an option, but in most cases, you can just have a single catch wherever the error can be handled properly.
Here, unless assignResolver itself needs to do something on encountering the error, leave out its catch entirely:
export async function assignResolver(data) {
csrf();
return api
.post("/api/task/assignResolver", data)
.then(function(res){
console.log("in api then block");
return res.data;
})
}
.catch is meant to handle the error, so afterwards the promise chain will continue regularily with the next .then. To continue with the next .catch you have to rethrow the error from inside the .catch or return a rejected promise.
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/
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);
});
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);
I use the following code to read json file and return a promise
I've two questions
return globAsync("folder/*.json").catch(function (err) {
throw new Error("Error read: " + err);
}).map(function (file) {
return fs.readFileAsync(file, 'utf8')
.then(function (res) {
console.log("test");
return JSON.parse(res);
},
function (err) {
throw new Error("Error :" + err);
}).then(function () {
console.log("test2");
});
});
I use the console log and I see that the console is printed twice
test
test
test2
test2
why its happening and how to avoid it ?
In the place I've put console.log("test2"); I need to invoke event
that the json parse is finished and still return outside the json object (to the caller), when I add the last then it doesn't work(the returned object is undefined),any idea how to do that right?
UPDATE I try like following which it doesn't work...
return globAsync("folder/*.json").catch(function (err) {
throw new Error("Error read: " + err);
}).map(function (file) {
return fs.readFileAsync(file, 'utf8')
.then(function (res) {
console.log("test");
JSON.parse(res); //data parse
}.catch(function (err) {
throw new Error("Error :" + err);
}
).then(function (data) {
obj.emit('ready');
return data;
}))
});
}
UPDATE2 I was able to solve it by simply add new return JSON.parse(res);
Now how should I solve the first issue which method called twice
Like #jaromandaX said, you probably got two *.json files. Try to print out the file name instead and it should become more obvious. In that case, .map is expected to be called twice, once for each file. Otherwise you aren't gonna be able to read and parse two files together.
If you want to get it to converge to a single point after all file reads and parses are complete, then you need to chain another .then after .map. eg.
return globAsync("folder/*.json")
.map(function(file) {
...
})
.then(function() {
obj.emit('ready');
});
EDIT To answer your question in comment. There are a few things you should keep in mind.
Throwing Error inside the promise chain will get caught by the promise and send it into the rejection flow. You may still throw an error if you are interested in getting custom error type or printing stack trace in a desirable way. But most people prefer return Promise.reject(error).
Any rejection in .map will send the promise chain into rejection flow.
Inside the rejection chain, if you want to continue down the rejection flow. You need to return Promise.reject(error), otherwise if you don't return a reject object, you can bring it back into resolve flow.
If you want to want to handle each error individually, you can do something like this:
return globAsync("folder/*.json")
.catch(function(error) {
// TODO: Handle error
return Promise.reject(error);
})
.map(function(file) {
return fs.readFileAsync(file, 'utf8')
.catch(function(error) {
// TODO: Handle error
return Promise.reject(error);
})
.then(function(res) {
return JSON.parse(res);
});
})
.then(function() {
obj.emit('ready');
});
If you want to handle once for glob and once for file read, then you have to get a bit more creative.
return globAsync("folder/*.json")
.catch(function(error) {
// TODO: Handle error
return Promise.reject(error);
})
.then(function(files) {
return Promise.resolve(files)
.map(function(file) {
return fs.readFileAsync(file, 'utf8');
})
.catch(function(error) {
// TODO: Handle error once for any read error
return Promise.reject(error);
})
.map(function(res) {
// Judging by your original code, you are not handling
// parser error, so I wrote this code to behave equivalent
// to your original. Otherwise chain parse immediate after
// readFileAsync.
return JSON.parse(res);
});
})
.then(function() {
obj.emit('ready');
});