Nested promise not throwing error in parent catch block - javascript

My code :
return resultSet.reduce (prev,next)=> {
return function1 ({
}).then(response => {
console.log('suscess' + someID)
return functionA (response.someID)
}).catch (err => {
console.log('failed' + someID)
return functionB (response.someID)
})
}, promise.resolve());
function1: function (){
return function2_Credentials().then{
return function3_insertSqlRecord().then{
return function4_appSearch().then (function(response){
return function5().then (return response)
.catch (function (error){
throw Error(error);
});
});
}.catch (function(error){
throw Error(error);
});
}
}.catch (function(error){
throw Error(error);
});
Inside my nested promise, if any of the inner functions failed I can get the error in catch block but it is not available function1 catch block. For example If i get function4_appSearch fails and return any error that error is accessible to the last catch block but not carried away until the function1's catch block. why am I not getting the error at console.log('failed' + someID) ? and how do I get access of error from child promise untill to the parent pormise's catch block?

Your current code isn't valid; it has multiple syntax errors, and everything ever passed to a .then needs to be a Promise. Instead of
return function3_insertSqlRecord().then{
return function4_appSearch().then
you should do something like
return function3_insertSqlRecord()
.then(function4_appSearch)
.then( // etc
This keeps your code flat and ensures that that the Promises each function generates are chained properly.
If you want the caller of function1 to handle the error, then just let the error propagate up the Promise chain - don't .catch inside function1, because whenever you .catch, a resolved Promise results (but you want the caller to be able to see a rejected Promise). You can explicitly throw inside the .catch to make the Promise reject, but if that's all you're doing inside the .catch, there isn't really any point.
Try this instead:
function function1() {
return function2_Credentials()
.then(function3_insertSqlRecord)
.then(function4_appSearch)
.then(function5);
}
There also isn't any point to using reduce if you aren't going to use the accumulator (here, prev) or the item in the array you're iterating over (next).

Related

How to fix stop promise returned in .catch beeing processed in the .then block of the preceding promise. Ie .catch should stay in .catch

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.

promise chain when rejected but only have then implermented

I was reading stuffs about promise and fetch and got really confused. I got the following code from Introduction to fetch.
My question is: what happens if status returns a rejected promise? then(json) is chained after then(status), does that mean then(json) won't do anything since then(json) only gets executed when status returnes a resolved promise? Or does that mean the chain just keeps passing all the thens if status returns rejected promise until it reaches reach catch at the bottom, and the catch catches error?
Or if I was wrong, what is the correct interpretation of this code?
function status(response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(response.statusText))
}
}
function json(response) {
return response.json()
}
fetch('users.json')
.then(status)
.then(json)
.then(function(data) {
console.log('Request succeeded with JSON response', data);
}).catch(function(error) {
console.log('Request failed', error);
});
In my early days of trying to understand promises, I thought of the .then chain as being two chains ... success and rejection
a rejection or error causes the "execution" to "jump" from success to rejection
if a rejection handler returns a value that isn't a rejected promised, the "execution" will "jump" to the success chain
Note: my earliest exposure to promises had no .catch ... because .then actually accepts two arguments onFullfilled and onRejected - if either of those is not a function it is ignored -
So, your code can be written as follows:
function status(response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(response.statusText))
}
}
function json(response) {
return response.json()
}
function log(data) {
console.log(data);
}
function handleError(error) {
console.log('Request failed', error);
}
fetch('users.json')
.then(status, null)
.then(json, null)
.then(log, null)
.then(null, handleError);
Now it's fairly clear that given an error in function stats, the "on rejected" chain is in "effect" (I really need to think of better terminology), and there's nothing in the reject chain until the very bottom, therefore, that's the next code that gets executed
Note .catch in some Promise libraries is simply the following
Promise.prototype.catch = function catch(onRejected) {
return this.then(null, onRejected);
};
When a promise gets rejected it goes directly to the .catch() without executing anything else of the chain.
So if status returns a Promise.reject only the catch function will execute.

I can't get the value of "result" in Node.js

In my console.log(info), I want to get the value of "result". But when I use console.log(info), I get Promise { <pending> }:
var info=new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (body.match('success') || body.match('code="25"')) {
resolve("success");
} else {
reject(body);
}
});
}).then(result => {
return result;
}).catch(err => {
console.log("error: " + err)
});
console.log(info);
I would like to get info == result. How can I do it?
Thanks
What happens here
First some explanation of what happens here. When you do something like this:
var info = new Promise((resolve, reject) => {
// ...
}).then(result => {
// ...
}).catch(err => {
// ...
});
then what ends up as the value of the info variable is a promise. That's because you start with a promise returned by the new Promise() constructor, you invoke its .then() method which returns a second promise, and on that second promise you invoke the .catch() method which returns a third promise - and this third promise is what gets saved into the info variable.
All of those method calls return immediately before the original HTTP request is finished so when you reach the next line:
console.log(info);
it's impossible to access the value of the response from the request() call because it didn't happen yet (the request() callback hasn't been called yet at this point). The info variable has a promise which is an object that you can use to register the callbacks that you want run when the value is eventually available. When you pass it to the console.log() it prints that it's a promise.
How to get the value
Now, when you want to print the value when it's finally available then you can attach a promise resolution callback to the promise that you have e.g. with a code like this:
info.then((value) => {
// you can use the value here
console.log('Value:', value);
}).catch((err) => {
// the promise got rejected
console.log('Error:', err);
});
If you are using a relatively recent version of Node (7.0+) then you could use await if you are inside of a function declared with an async keyword, to get the resolution value of the promise like this:
(async function () {
let value = await info;
console.log(value);
})();
or shorter:
(async () => {
console.log(await info);
})();
(If you are already inside of an async function then you don't need the (async () => { ... })(); wrapper.)
How it works
What the await keyword does is it yields the promise from an implicit generator function that passes the control to the outer coroutine control code which attaches a resolution and rejection handlers to that yielded promise and starts the generator again by either returning the resolved value from the await operator or raising an exception if the promise was rejected. The generator can then continue using the return value and catching the exception, or it can let the exception bubble to the outer blocks where it can be caught or converted to a rejection of the implicit promise returned by the async function if not handled along the way.
How you can use it
It may seem complicated but from the point of view of your code it lets you do things like:
let value = await fun();
(where fun() is a function that returns a promise) and have the resolved value of the promise available in the value variable (the real value, not a promise).
Remember that the await keyword throws an exception when the promise in question gets rejected. To handle that case you can use a try/catch block:
try {
let value = await fun();
// promise got resolved, you have value here:
console.log('Value:', value);
} catch (error) {
// promise got rejected, you have error here:
console.log('Error:', error);
}
which is equivalent of this code without the new syntax:
fun().then((value) => {
// promise got resolved, you have value here:
console.log('Value:', value);
}).catch((error) => {
// promise got rejected, you have error here:
console.log('Error:', error);
});
with the main difference being the variable scoping when you await on multiple promises in a single try block as opposed to using multiple chained .then() handlers, each returning a new promise.
Your code looked like it used await but it didn't
I added the example of how to fix your code with await because you wrote your code as if this:
var info = new Promise(...);
// here the 'info' variable is set to a promise
was really this:
var info = await new Promise(...);
// here the 'info' variable is set to the value
// that the promise eventually resolves to
More info
For more info, see:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
Node support
For support of that syntax in Node versions, see:
http://node.green/#ES2017-features-async-functions
In places where you don't have native support for async and await you can use Babel:
https://babeljs.io/docs/plugins/transform-async-to-generator/
or with a slightly different syntax a generator based approach like in co or Bluebird coroutines:
https://www.npmjs.com/package/co
http://bluebirdjs.com/docs/api/promise.coroutine.html
In your code, info is a promise. Thus, you don't compare info to anything. To get access to the result in a promise, you use .then() on the promise as in:
info.then(result => {
// test result here
}).catch(err => {
// handle error here
});
In addition, your .catch() handler is "eating" the error after logging it. If you don't rethrow the error or return a rejected promise from a .catch() handler, then the error is considered "handled" and the promise state changes to fulfilled.
So, you can do this:
let info = new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (body.match('success') || body.match('code="25"')) {
resolve("success");
} else {
reject(body);
}
});
}).catch(err => {
console.log("error: " + err);
// rethrow error so promise stays rejected
throw err;
});
info.then(result => {
// test result here
}).catch(err => {
// handle error here
});

Inner promise returning a catch

Will the promise rejection that is returned inside catch gonna get received outside of the outer promise?
promisedFunction().then((result) => {
return anotherPromisedFunction().then((result) => {
....
}).catch((error) => {
return Promise.reject(error);
});
}).catch((error) => {
//catch inner error here
});;
The then method returns a Promise, in your case, you are returning a rejected promise, so yes, the outer catch should handle that.

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);

Categories

Resources