Подтвердить что ты не робот

Возможно необработанное отклонение в Angular 1.6

У меня есть код с 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);
  };
})

не помогает вообще. В обработчике ошибок я уже получил "завернутую" ошибку.

4b9b3361

Ответ 1

Это исправлено с помощью 316f60f, и исправление включено в v1.6.1 выпуск.

Ответ 2

Я исправил ту же проблему с версией 1.6.1, обновив angular -ui-router до 0.3.2.

Ответ 3

Первый вариант - просто скрыть ошибку с disablinconfiguring errorOnUnhandledRejections в $qProvider configuratio, как предложено Cengkuru Michael:

app.config(['$qProvider', function ($qProvider) {
    $qProvider.errorOnUnhandledRejections(false);
}]);

НО, это приведет к отключению регистрации. Сама ошибка останется

Лучшее решение в этом случае будет: обработка отклонения с помощью метода .catch():

service.doSomething()
    .then(function (response) {})
    .catch(function (err) {});

Полезные ссылки:

Ответ 4

Я получил такую ​​же необработанную ошибку отклонения, когда отклоненное обещание не обрабатывается angular -ui-router (ui-sref) с помощью angular ver1.6.1, и эта функция включена по умолчанию.

Для тех, кто хочет обходной путь (не рекомендуется), вы можете глобально отключить необработанные обещания, такие как:

app.config(['$qProvider', function ($qProvider) { $qProvider.errorOnUnhandledRejections(false); }]);

Ответ 5

Есть еще один случай, добавив обработчик finally() к обещанию, генерирующему ошибку: http://plnkr.co/edit/eT834BkIEooAMvrVcLDe

Потому что finally() создает новое обещание и вызывает на нем преобразователь. (Отклонение второго в случае отклонения)

Я установил исправление в plnkr, но он выглядит не очень хорошо.

Ответ 6

Эта информация помогла мне отследить, что (в моем случае) создавало обещание и не добавляло обработчик ошибок. Я нашел его погребенным в обсуждении вопроса # 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.

Ответ 7

У меня проблема даже с версией 1.6.1 в моем httpErrorInterceptor, для одного usecase my, если мой api return 404 мне нужно попробовать другой запрос с другими данными... поэтому в этом случае я отклоняю запрос и angular выбросить необработанную ошибку отклонения...

Я устанавливаю 1.5.9, и теперь больше нет ошибок!

Ответ 8

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?

Ответ 9

Я решил эту ошибку, добавив значение по умолчанию в блок catch, например:

service.doSomething()
    .then(function(response) {
        var x = null;
        var y = x.y;
    }).catch(function(error) {
        var y = 0;
    });

(учтите, что я не опытный разработчик angular)