web-dev-qa-db-fra.com

Rejet éventuellement non pris en charge dans Angular 1.6

J'ai un code avec AngularJS:

service.doSomething()
  .then(function(result) {
      //do something with the result
  });

Dans AngularJS 1.5.9 quand j'ai une erreur dans la section .then() comme:

service.doSomething()
  .then(function(result) {
      var x = null;
      var y = x.y;
      //do something with the result
  });

Je reçois un message d'erreur clair:

TypeError: Impossible de lire la propriété 'y' de null

Mais dans la version 1.6 avec le même code, je reçois une erreur différente:

Rejet éventuellement non traité: {} non défini

Je sais que cela est lié à ce changement , et la solution unique est assez simple en ajoutant le bloc .catch():

service.doSomething()
  .then(function(result) {
      var x = null;
      var y = x.y;
      //do something with the result
  })
  .catch(console.error);

Maintenant, j'ai encore ce que je veux:

TypeError: Impossible de lire la propriété 'y' de null

Mais comment obtenir le même résultat (erreur plus détaillée) pour l’ensemble de l’application sans ajouter le bloc .catch() à chaque endroit?

J'ai testé la solution suggérée pour le désactiver en ajoutant:

$qProvider.errorOnUnhandledRejections(false);

Mais avec cela, la situation est encore pire - je n'ai rien dans la console! L'erreur est avalée quelque part et n'est pas enregistrée du tout. Je ne suis pas sûr que ce soit un problème avec AngularJS 1.6 ou avec ma configuration.

Avez-vous des idées pour "restaurer" le comportement de journalisation à partir de la version 1.5.9?

MODIFIER:

Ajout d'un gestionnaire d'erreur personnalisé:

.factory('$exceptionHandler', function($log) {
  return function(exception, cause) {
    $log.warn(exception, cause);
  };
})

ne aide pas du tout. Dans le gestionnaire d'erreurs, je reçois déjà l'erreur "encapsulée".

26
Piotr Pradzynski

Ce problème a été corrigé avec fix ($ q): Ajoutez un retour arrière au rejet des promesses non gérées - Commit 316f60f et le correctif est inclus dans v1.6.1 release .

17
gkalpak

La première option consiste simplement à masquer une erreur avec disablinconfiguring errorOnUnhandledRejections dans $ qProvider configuration comme suggéré/ Cengkuru Michael :

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

MAIS cela ne fera que désactiver la journalisation. L'erreur elle-même restera 

La meilleure solution dans ce cas sera - gérer un rejet avec la méthode .catch():

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

Liens utiles:

14
Andrii Verbytskyi

J'ai corrigé le même problème avec la version 1.6.1 en mettant à jour angular-ui-router en 0.3.2. 

8
Stephen C

Cette information m'a aidé à localiser ce qui (dans mon cas) créait la promesse sans ajouter de gestionnaire d'erreur. Je l'ai trouvé enterré dans la discussion du numéro # 2889 "Rejet éventuellement non géré avec Angular 1.5.9" .

Le Gist, est, patch $q pour mettre en cache une trace de pile lors de la création de promesses, de sorte qu'elle puisse être récupérée lorsque l'erreur est déclenchée.

Pour ce faire, insérez ce code pour décorer $q quelque part vers le haut de votre application angulaire:

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

Recherchez ensuite dans le code angulaire le message "éventuellement un rejet non géré" et placez un point d'arrêt sur cette ligne. Lorsque le point d'arrêt est atteint, affichez la valeur toCheck.stack sur la console et vous verrez à peu près ceci:

>> toCheck.stack
"set@http://localhost:8000/js/dual-site.js:18:19
Promise@http://localhost:8000/js/angular.js:17008:22
then@http://localhost:8000/js/angular.js:17016:20
catch@http://localhost:8000/js/angular.js:17026:14
SyncStrategy.prototype.send@http://localhost:8000/js/angular-state-machine.js:436:24
StateMachine/this.send@http://localhost:8000/js/angular-state-machine.js:235:16

Le code incriminé est la fonction catch/then de l’appel de la trame.

4
wu-lee

J'ai la même erreur de rejet non gérée lorsqu'une promesse refusée n'est pas gérée par angular-ui-router (ui-sref) à l'aide de angular ver1.6.1 & Cette fonctionnalité est activée par défaut. 

Pour tous ceux qui veulent une solution de contournement (non recommandé, cependant), vous pouvez globalement faire taire les refus de promesses non gérées de ce type -

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

3
Yash Vekaria

Il y a un autre cas, ajouter un gestionnaire finally() à une promesse génère l'erreur: http://plnkr.co/edit/eT834BkIEooAMvrVcLDe

Parce que finally() crée une nouvelle promesse et appelle le résolveur dessus. (Rejeter un 2e dans un cas de rejet)

J'ai mis un correctif dans la commande mais il ne semble pas très bien.

3
Rouche

J'ai le problème même avec la version 1.6.1 dans mon httpErrorInterceptor, pour une utilisation mon cas si mon api retourne 404 je dois essayer une autre demande avec d'autres données ... donc dans ce cas je rejette seulement la demande et jette angulairement le rejet non géré Erreur...

J'installe 1.5.9 et maintenant il n'y a plus d'erreur!

0
lolo

J'ai résolu cette erreur en ajoutant une valeur par défaut dans le bloc catch comme:

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

(comptez que je ne suis pas un développeur angulaire expérimenté)

0
onlyjunior

errorOnUnhandledRejections (false); n'était pas une résolution pour moi.

Vous avez en effet besoin de définir un gestionnaire d'exceptions ... cependant ... enveloppez-le dans une fonction de délai d'attente: cela forcera la trace d'exception/de pile à être renvoyée. 

Pour que l'erreur apparaisse comme une erreur dans la console Web, comme vous l'aviez initialement prévu:

ng.factory('$exceptionHandler', function($log) {
  return function(exception, cause) {
    // do some some stuff...
    setTimeout(function(){
      // throw the original exception (with correct line #'s etc)
      throw exception;
    })
  };
});

Heres l'astuce de délai d'attente: Pourquoi ne puis-je pas jeter dans un gestionnaire Promise.catch?

0
nawlbergs