你肯定使用的承诺机制错误,抛出一个用户定义的throw语句不构成捕它作为承诺拒绝妥善。由于$q
文件中指出:
当比较deferreds /承诺 的try/catch /抛出熟悉的行为,认为拒绝在JavaScript中的扔关键字。 这也意味着,如果您通过承诺错误 回调“发现”错误,并且您希望将错误转发给当前承诺的承诺,则必须通过返回 通过返回 拒绝来“重新抛出”错误拒绝。
它们类似但不等同,为了捕获用户定义的throw语句,应该使用catch
语句块。虽然$q
承诺应该只有catch
拒绝承诺。因此,在你的情况下,返回被拒绝的承诺是处理该过程的正确方式,而不是抛出用户定义的异常。
DEMO
JAVASCRIPT
describe('Q Service Test', function() {
var $q,
$rootScope;
beforeEach(inject(function(_$q_, _$rootScope_) {
$q = _$q_;
$rootScope = _$rootScope_;
}));
it('Rejected promises are handled properly', function() {
var state = 'ok';
$q.when(1)
.then(function() {
return $q.reject('rejected');
})
.catch(function() {
state = 'error';
});
$rootScope.$digest();
expect(state).toBe('error');
});
});
UPDATE:
为什么你的代码具有这样的浏览器,是因为角度的$q
实现使用try/catch
声明的原因块处理承诺队列。当任何回调抛出任何错误时,它自己捕获错误,拒绝它作为拒绝的原因,之后它使用$exceptionHandler
来记录错误。我建议你简单地退回被拒绝的承诺。
至于为什么单元测试这样的行为的原因是因为angular-mocks
实施$exceptionHandler
与实际应用的$exceptionHandler
不同。前者创建一个具有不同模式的提供者,默认的angular-mocks实现使用rethrow
模式,该模式继而抛出异常而不是记录它。如果您希望单元测试的行为与默认应用程序的$exceptionHandler
相同,则可以将模式设置为'log'
。
DEMO
JAVASCRIPT
describe('Q Service Test', function() {
var $q,
$rootScope;
beforeEach(module('ng', function($exceptionHandlerProvider) {
$exceptionHandlerProvider.mode('log');
}));
beforeEach(inject(function(_$q_, _$rootScope_) {
$q = _$q_;
$rootScope = _$rootScope_;
}));
it('Caught exceptions are handled properly', function() {
var state = 'ok';
$q.when(1)
.then(function() {
throw new Error();
})
.catch(function() {
state = 'error';
});
$rootScope.$digest();
expect(state).toBe('error');
});
});
感谢您的详细解答。还有一个问题 - 我的带'throw'的版本怎么只能通过测试,并且在浏览器中按预期工作,除了被传递到'.catch'块? – Impworks
你已经提到它**在浏览器**中按预期工作,那么你可以显示该部分的代码? – ryeballar
当然是:https://jsfiddle.net/eqf54zzm/ – Impworks