你肯定使用的承諾機制錯誤,拋出一個用戶定義的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