如何正确地捕捉承诺中的错误?

我觉得这两件事并不相同:

return somePromise() .then() .then() .then() .catch(function(e) { throw e; }); 

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

第一个片段只会捕获最新的错误(其他错误将会丢失),而第二个片断将捕获链中任何位置的错误。

但是我必须错过一些东西,因为强迫用户在每一个承诺失败之后都要记住抓住承诺的目的。

我误解和放置一个.catch()最后会捕捉链中的任何错误?

在第一种情况下,如果任何一个处理程序正在抛出一个错误,那么这个错误将被捕获到最后一个catch处理程序。

在第二种情况下,如果任何一个处理程序抛出一个错误,则该错误将发送到最近的catch处理程序。 当你在catch处理程序中抛出错误时,它只会转到下一个最近的catch处理程序。

我误解和放置一个.catch()最后会捕捉链中的任何错误?

不,在大多数情况下, catch承诺链的最后是正确的。 但是,如果因为中间失败而不希望失败整个承诺链,那么可以返回catch处理程序中下一个处理程序使用的值。

只是增加了这个最好的答案。 下面是你的两个代码片段在同步代码中的外观:

 return somePromise() .then() .then() .then() .catch(function(e) { throw e; }); 

变为:

 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 } 

第二个例子:

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

成为,不是很有趣:

 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 } } 

有些样本可以更好地理解有承诺的错误。

您必须运行该代码段并将结果与​​代码进行比较,以了解发生了什么。

在这个例子中,我们有:

  • 4testing我们在哪里有一个Promise链,在其中我们抛出错误。
  • 4种方式来处理错误。

这个例子试图展示4种不同的方式来处理错误和结果。

我希望这可以帮助别人!

 /* * 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">&nbsp;</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>