Nous avons un modèle de résolution de promesses dans notre application Angular qui nous a bien servi jusqu'à Angular 1.6.0:
resource.get().$promise
.then(function (response) {
// do something with the response
}, function (error) {
// pass the error the the error service
return errorService.handleError(error);
});
Et voici comment nous déclenchons l'erreur dans Karma:
resourceMock.get = function () {
var deferred = $q.defer();
deferred.reject(error);
return { $promise: deferred.promise };
};
Maintenant, avec la mise à jour vers la version 1.6.0, Angular se plaint soudain dans nos tests unitaires (en karma) des promesses rejetées avec une erreur "Rejet éventuellement non géré". Mais nous traitons le rejet dans la deuxième fonction qui appelle notre service d’erreur.
Que recherche exactement Angular ici? Comment veut-il que nous "gérions" le rejet?
Essayez d'ajouter ce code à votre configuration. J'ai eu un problème similaire une fois, et cette solution de contournement a fait l'affaire.
app.config(['$qProvider', function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
}]);
Le code que vous montrez gérera un rejet qui se produit avant l'appel à .then
. Dans une telle situation, le deuxième rappel que vous passez à .then
sera appelé et le rejet sera traité.
Cependant , lorsque la promesse sur laquelle vous appelez .then
réussit, le premier rappel est appelé. Si ce rappel lève une exception ou retourne une promesse refusée, le rejet résultant ne sera pas traité , car le deuxième rappel ne gérera pas les refus en raison du 1er C’est ainsi que les implémentations de promesse conformes à la spécification Promises/A + et à Angular promesses sont conformes.
Vous pouvez illustrer cela avec le code suivant:
function handle(p) {
p.then(
() => {
// This is never caught.
throw new Error("bar");
},
(err) => {
console.log("rejected with", err);
});
}
handle(Promise.resolve(1));
// We do catch this rejection.
handle(Promise.reject(new Error("foo")));
Si vous l'exécutez dans Node, qui est également conforme à Promises/A +, vous obtenez:
rejected with Error: foo
at Object.<anonymous> (/tmp/t10/test.js:12:23)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:509:3
(node:17426) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: bar
Résoudre le problème en revenant à Angular 1.5.9 et en réexécutant le test. Il s’agissait d’un problème d’injection simple, mais Angular 1.6.0 l’a remplacé en générant à la place l’erreur "Rejet éventuellement non géré", masquant ainsi l’erreur réelle.
La première option consiste simplement à masquer une erreur en la désactivant en configurant errorOnUnhandledRejections
dans la configuration $ qProvider comme suggéré Cengkuru Michael
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(fn)
:
resource.get().$promise
.then(function (response) {})
.catch(function (err) {});
LIENS:
Pour éviter d'avoir à taper .catch(function () {})
supplémentaire dans votre code à plusieurs endroits, vous pouvez ajouter un decorator
au $exceptionHandler
.
C’est une option plus détaillée que les autres, mais vous n’avez qu’à effectuer le changement à un endroit.
angular
.module('app')
.config(configDecorators);
configDecorators.$inject = ["$provide"];
function configDecorators($provide) {
$provide.decorator("$exceptionHandler", exceptionHandler);
exceptionHandler.$inject = ['$delegate', '$injector'];
function exceptionHandler($delegate, $injector) {
return function (exception, cause) {
if ((exception.toString().toLowerCase()).includes("Possibly unhandled rejection".toLowerCase())) {
console.log(exception); /* optional to log the "Possibly unhandled rejection" */
return;
}
$delegate(exception, cause);
};
}
};
Veuillez vérifier la réponse ici:
Rejet éventuellement non traité dans Angular 1.6
Ce problème a été résolu avec 16f60f et le correctif est inclus dans la version version 1.6.1 .
Vous pouvez masquer le problème en désactivant errorOnUnhandledRejections, mais l'erreur indique que vous devez "gérer un éventuel rejet", il vous suffit donc d'ajouter un verrou à votre promesse.
resource.get().$promise
.then(function (response) {
// do something with the response
}).catch(function (error)) {
// pass the error to the error service
return errorService.handleError(error);
});
Référence: https://github.com/angular-ui/ui-router/issues/2889
J'ai observé le même comportement lors de l'exécution du test. Il est étrange que le code de production fonctionne correctement et échoue uniquement lors des tests.
La solution facile pour rendre vos tests heureux consiste à ajouter catch(angular.noop)
à votre maquette de promesse. Dans l'exemple ci-dessus, il devrait ressembler à ceci:
resourceMock.get = function () {
var deferred = $q.defer();
deferred.reject(error);
return { $promise: deferred.promise.catch(angular.noop) };
};
J'étais également confronté au même problème après la mise à jour vers Angular 1.6.7, mais lorsque j'ai examiné le code, une erreur s'est produite pour $interval.cancel(interval);
pour mon cas.
Mon problème a été résolu une fois que j'ai mis à jour angular-mocks
vers la dernière version (1.7.0).
Ce n'est peut-être pas votre situation particulière, mais j'ai eu un problème similaire.
Dans mon cas, j'utilisais angular-i18n et obtenais le dictionnaire de paramètres régionaux de manière asynchrone. Le problème était que le fichier json qu'il obtenait était mal mis en retrait (mélange d'espaces et de tabulations). La requête GET n'a pas échoué.
Corriger l'indentation a résolu le problème.
J'ai eu cette même notification apparaît après avoir apporté quelques modifications. Il s’est avéré que c’est parce que j’avais changé entre une seule demande $http
à plusieurs demandes utilisant le service angularjs $q
.
Je ne les avais pas emballés dans un tableau. par exemple.
$q.all(request1, request2).then(...)
plutôt que
$q.all([request1, request2]).then(...)
J'espère que cela permettra à quelqu'un de gagner du temps.