Reputation: 1079
I am under the impression that these two things are not equivalent:
return somePromise()
.then()
.then()
.then()
.catch(function(e) { throw e; });
and
return somePromise()
.catch(function(e) { throw e; });
.then()
.catch(function(e) { throw e; });
.then()
.catch(function(e) { throw e; });
.then()
.catch(function(e) { throw e; });
The first snippet will only catch errors on the latest then (the other errors will be lost) whereas the second snippet will catch any error anywhere along the chain.
But I must be missing something because forcing the user to remember putting a catch after every promise defeats the purpose of promises.
Am I misunderstanding and placing a .catch()
last will catch any error along the chain?
Upvotes: 4
Views: 1859
Reputation: 276286
Just adding to thefourtheye's great answer. Here is how your two code snippets look in synchronous code:
return somePromise()
.then()
.then()
.then()
.catch(function(e) { throw e; });
Becomes:
try {
var val = someFunction();
val = fn(val); // p.then(x => ...);
//...
return val;
} catch (e) {
throw e; // this catch didn't actually do anything, but will be reached if someFunction
// throws an error during execution
}
The second example:
return somePromise()
.catch(function(e) { throw e; });
.then()
.catch(function(e) { throw e; });
.then()
.catch(function(e) { throw e; });
.then()
.catch(function(e) { throw e; });
Becomes, the not very interesting:
try {
try {
var val = someFunction();
return val;
} catch (e) {
throw e;
}
val = fn(val); // this is a then(); If it's really an empty then - a noop
} catch (e) {
throw e;
}
val = fn(val); // this is a then(); If it's really an empty then - a noop
} catch (e) {
throw e;
}
val = fn(val); // this is a then(); If it's really an empty then - a noop
} catch (e) {
throw e; // yep, even this last one will be reached
}
}
Upvotes: 2
Reputation: 3042
You have to run the snippet and compare the result with the code to understand what happen.
In this sample we have :
This sample try to show 4 different ways to handle the errors, and the result.
I hope this can help someone !
/*
* This part is only utility functions
* dont care about that
*/
var el = $('#dbg');
var fn = {
log: function(val ) {
el.append('<pre class="line">' + val + '</pre>');
return val;
},
err : function(val, forced){
var errNumber = forced ? val : 404;
fn.log('<div class="thr">throwing an error : ' + errNumber + '</div>' );
throw errNumber;
},
ok: function(val) {
fn.log('<div class="ok">received : ' + val + ' | returning : ' + (val+1) + '</div>');
return val+1;
},
ko: function(val) {
fn.log('<div class="ko">received : ' + val + ' | returning : ' + (val-1) + '</div>');
return val-1;
},
catch : function(val){
fn.log('<div class="ko">FROM CATCH : \treceived : ' + val + ' | returning : ' + val + '</div>');
return val;
},
sep : function(val){
fn.log('<div class="sep"> </div>');
return val;
},
};
fn.log('Each fn.ok increment + 1 => fn.ok(5) : log 5 in a green line and return 6');
fn.ok(5);
fn.log('');
fn.log('Each fn.ko decrement - 1 => fn.ko(5) : log 5 in a red line and return 4');
fn.ko(5);
/*
*
* Each fn.ok increment + 1
* Each fn.ko decrement - 1
*
*/
/*
* Test 1 :
*
* only one catch at end
*
*/
var p = Promise.resolve()
.then(function(){
var val = 1;
fn.sep();
fn.log('start test : ' + val);
fn.log('\n\tonly one catch at end\n<hr>');
fn.log('Promise.resolve(1)\n\t.then(fn.ok)\n\t.then(fn.ok)\n\t.then(fn.ok)\n\t .then(fn.err)\n\t.then(fn.ok)\n\t.then(fn.ok)\n\t.then(fn.ok)\n\t.catch(fn.catch)');
return val;
})
.then(fn.ok)
.then(fn.ok)
.then(fn.ok)
.then(fn.err)
.then(fn.ok)
.then(fn.ok)
.then(fn.ok)
.catch(fn.catch)
;
/*
* Test 2 :
*
* same as test 1
* only one catch at end
* but we start by an error
*
*/
p = p.then(function(){
var val = 2;
fn.sep();
fn.log('start test : ' + val);
fn.log('\n\tsame as test 1\n\tonly one catch at end\n\tbut we start by an error\n<hr>');
fn.log('Promise.resolve()\n\t .then(fn.err)\n\t.then(fn.ok)\n\t.then(fn.ok)\n\t.then(fn.ok)\n\t .then(fn.err)\n\t.then(fn.ok)\n\t.then(fn.ok)\n\t.then(fn.ok)\n\t.catch(fn.catch)');
return fn.err();
})
.then(fn.ok)
.then(fn.ok)
.then(fn.ok)
.then(fn.err)
.then(fn.ok)
.then(fn.ok)
.then(fn.ok)
.catch(fn.catch)
;
/*
* Test 3 :
*
* same as test 2
* we start by an error
* but each one is chained
* to a catcher
*
*/
p = p.then(function(){
var val = 3;
fn.sep();
fn.log('start test : ' + val);
fn.log('\n\tsame as test 2\n\twe start by an error\n\tbut each one is chained\n\tto a catcher\n<hr>');
fn.log('Promise.resolve('+val+')\n\t .then(fn.err)\n\t.then(fn.ok).catch(fn.catch)\n\t.then(fn.ok).catch(fn.catch)\n\t.then(fn.ok).catch(fn.catch)\n\t .then(fn.err)\n\t.then(fn.ok).catch(fn.catch)\n\t.then(fn.ok).catch(fn.catch)\n\t.then(fn.ok).catch(fn.catch)\n\t.catch(fn.catch)');
return fn.err(val , true);
})
.then(fn.ok).catch(fn.catch)
.then(fn.ok).catch(fn.catch)
.then(fn.ok).catch(fn.catch)
.then(fn.err)
.then(fn.ok).catch(fn.catch)
.then(fn.ok).catch(fn.catch)
.then(fn.ok).catch(fn.catch)
.catch(fn.catch)
;
/*
* Test 4 :
*
* same as test 2
* we start by an error
* but each one have
* a rejected handler
*
*/
p = p.then(function(){
var val = 4;
fn.sep();
fn.log('start test : ' + val);
fn.log('\n\tsame as test 2\n\twe start by an error\n\tbut each one have\n\ta rejected handler\n<hr>');
fn.log('Promise.resolve('+val+')\n\t .then(fn.err)\n\t.then(fn.ok , fn.ko)\n\t.then(fn.ok , fn.ko)\n\t.then(fn.ok , fn.ko)\n\t .then(fn.err , fn.ko)\n\t.then(fn.ok , fn.ko)\n\t.then(fn.ok , fn.ko)\n\t.then(fn.ok , fn.ko)\n\t.catch(fn.catch)');
return fn.err(val , true);
})
.then(fn.ok , fn.ko)
.then(fn.ok , fn.ko)
.then(fn.ok , fn.ko)
.then(fn.err , fn.ko)
.then(fn.ok , fn.ko)
.then(fn.ok , fn.ko)
.then(fn.ok , fn.ko)
.catch(fn.catch)
;
.line{
border:solid 1px transparent;
margin : 3px;
padding : 3px;
}
.line .ok,
.line .ko,
.line .thr{
margin-left : 24px;
padding-left : 3px;
}
.ok{
background : #9F9;
}
.ko{
background : #F99;
}
.thr{
background : #666;
color : #DDD;
}
.sep{
border:solid 1px #666;
background : #CCF;
border-radius : 12px;
margin-top : 21px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://raw.githubusercontent.com/jakearchibald/es6-promise/master/dist/es6-promise.min.js"></script>
<div id='dbg'></div>
Upvotes: 0
Reputation: 239443
In the first case, if any of the then
handlers are throwing an error, then that error will be caught at the last catch
handler.
In the second case, if any of the then
handlers throw an error, that error will go to the nearest catch
handler. As you throw the error in catch
handlers as well, it will simply go to the next nearest catch
handler.
Am I misunderstanding and placing a .catch() last will catch any error along the chain?
Nope, catch
at the end of the promise chain is the right thing to do in most of the cases. But, in case if you don't want to fail the entire chain of promises because of an intermediate failure, then you can return the value to be used by the next then
handler in the catch
handler.
Upvotes: 4