Ответ 1
Это исправлено с помощью 316f60f, и исправление включено в v1.6.1 выпуск.
У меня есть код с AngularJS:
service.doSomething()
.then(function(result) {
//do something with the result
});
В AngularJS 1.5.9, когда у меня есть ошибка в разделе .then()
, например:
service.doSomething()
.then(function(result) {
var x = null;
var y = x.y;
//do something with the result
});
Я получаю сообщение об ошибке:
TypeError: Невозможно прочитать свойство 'y' null
Но в версии 1.6 с тем же кодом у меня возникает другая ошибка:
Возможно необработанное отклонение: {} undefined
Я знаю, что это связано с это изменение, а одно решение довольно просто, добавив блок .catch()
:
service.doSomething()
.then(function(result) {
var x = null;
var y = x.y;
//do something with the result
})
.catch(console.error);
Теперь у меня снова есть то, что я хочу:
TypeError: Невозможно прочитать свойство 'y' null
Но как получить тот же результат (более подробную ошибку) для всего приложения без добавления блока .catch()
в каждом месте?
Я протестировал предлагаемое решение, чтобы отключить его, добавив:
$qProvider.errorOnUnhandledRejections(false);
Но с этим ситуация еще хуже - у меня нет НИКАКОГО в консоли! Ошибка проглатывается где-то и вообще не регистрируется. Я не уверен, что это проблема с AngularJS 1.6 или с моей конфигурацией.
Есть ли у вас какие-либо идеи о том, как "восстановить" поведение журнала с версии 1.5.9?
EDIT:
Добавление настраиваемого обработчика ошибок:
.factory('$exceptionHandler', function($log) {
return function(exception, cause) {
$log.warn(exception, cause);
};
})
не помогает вообще. В обработчике ошибок я уже получил "завернутую" ошибку.
Это исправлено с помощью 316f60f, и исправление включено в v1.6.1 выпуск.
Я исправил ту же проблему с версией 1.6.1, обновив angular -ui-router до 0.3.2.
Первый вариант - просто скрыть ошибку с disablinconfiguring errorOnUnhandledRejections
в $qProvider configuratio, как предложено Cengkuru Michael:
app.config(['$qProvider', function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
}]);
НО, это приведет к отключению регистрации. Сама ошибка останется
Лучшее решение в этом случае будет: обработка отклонения с помощью метода .catch()
:
service.doSomething()
.then(function (response) {})
.catch(function (err) {});
Полезные ссылки:
Я получил такую же необработанную ошибку отклонения, когда отклоненное обещание не обрабатывается angular -ui-router (ui-sref) с помощью angular ver1.6.1, и эта функция включена по умолчанию.
Для тех, кто хочет обходной путь (не рекомендуется), вы можете глобально отключить необработанные обещания, такие как:
app.config(['$qProvider', function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
}]);
Есть еще один случай, добавив обработчик finally()
к обещанию, генерирующему ошибку:
http://plnkr.co/edit/eT834BkIEooAMvrVcLDe
Потому что finally()
создает новое обещание и вызывает на нем преобразователь. (Отклонение второго в случае отклонения)
Я установил исправление в plnkr, но он выглядит не очень хорошо.
Эта информация помогла мне отследить, что (в моем случае) создавало обещание и не добавляло обработчик ошибок. Я нашел его погребенным в обсуждении вопроса # 2889 "Возможно необработанное отклонение с Angular 1.5.9" .
Суть заключается в патче $q
для кэширования трассировки стека при создании promises, чтобы его можно было получить при срабатывании ошибки.
Чтобы сделать это, вставьте этот код, чтобы украсить $q
где-то в верхней части вашего Angular приложения:
// Decorate the $q service when app starts
app.decorator('$q', ["$delegate", function($delegate) {
// Create a new promise object
var promise = $delegate.when();
// Access the `Promise` prototype (nonstandard, but works in Chrome)
var proto = promise.__proto__;
// Define a setter for `$$state` that creates a stacktrace
// (string) and assigns it as a property of the internal `$$state` object.
Object.defineProperty(proto, '$$state', {
enumerable: true,
set: function(val) {
val.stack = new Error().stack;
this._$$state = val;
},
get: function() {
return this._$$state;
}
});
return $delegate;
}]);
Затем найдите код Angular для сообщения "возможно необработанное отклонение" и поместите точку останова на эту строку. Когда точка останова достигнута, распечатайте значение toCheck.stack
на консоли, и вы увидите что-то вроде этого:
>> toCheck.stack
"[email protected]://localhost:8000/js/dual-site.js:18:19
[email protected]://localhost:8000/js/angular.js:17008:22
[email protected]://localhost:8000/js/angular.js:17016:20
[email protected]://localhost:8000/js/angular.js:17026:14
[email protected]://localhost:8000/js/angular-state-machine.js:436:24
StateMachine/[email protected]://localhost:8000/js/angular-state-machine.js:235:16
Оскорбительный код - это кадр, вызывающий Angular функции catch/then.
У меня проблема даже с версией 1.6.1 в моем httpErrorInterceptor, для одного usecase my, если мой api return 404 мне нужно попробовать другой запрос с другими данными... поэтому в этом случае я отклоняю запрос и angular выбросить необработанную ошибку отклонения...
Я устанавливаю 1.5.9, и теперь больше нет ошибок!
errorOnUnhandledRejections (ложь); для меня не было решением.
Вам действительно нужно определить обработчик исключений... однако... оберните его в функцию тайм-аута: это заставит бросать исходную трассировку исключения/стека.
Чтобы сообщение об ошибке появилось как ошибка в веб-консоли, как вы изначально планировали:
ng.factory('$exceptionHandler', function($log) {
return function(exception, cause) {
// do some some stuff...
setTimeout(function(){
// throw the original exception (with correct line # etc)
throw exception;
})
};
});
Вот трюк тайм-аута: Почему я не могу бросить внутри обработчика Promise.catch?
Я решил эту ошибку, добавив значение по умолчанию в блок catch, например:
service.doSomething()
.then(function(response) {
var x = null;
var y = x.y;
}).catch(function(error) {
var y = 0;
});
(учтите, что я не опытный разработчик angular)