javascript - Posiblemente rechazo no manejado en Angular 1.6
angularjs angular-promise (9)
Esta información me ayudó a rastrear qué (en mi caso) estaba creando la promesa y no agregar un controlador de errores. Lo encontré enterrado en la discusión del número 2889 "Posiblemente rechazo no manejado con Angular 1.5.9" .
Lo esencial, es, parche $q
para almacenar en caché un seguimiento de la pila al crear promesas, de manera que se pueda recuperar cuando se desencadena el error.
Para hacerlo, inserte este código para decorar $q
algún lugar cerca de la parte superior de su aplicación 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;
}]);
Luego busque en el código angular el mensaje "posible rechazo no manejado" y coloque un punto de interrupción en esa línea. Cuando se alcance el punto de interrupción, imprima el valor de toCheck.stack
en la consola, y verá algo como esto:
>> 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
El código ofensivo es el cuadro que llama a las funciones catch / then de angular.
Tengo un código con AngularJS:
service.doSomething()
.then(function(result) {
//do something with the result
});
En AngularJS 1.5.9 cuando tengo un error en la sección .then()
como:
service.doSomething()
.then(function(result) {
var x = null;
var y = x.y;
//do something with the result
});
Me sale un mensaje de error claro:
TypeError: No se puede leer la propiedad ''y'' de null
Pero en la versión 1.6 con el mismo código obtengo un error diferente:
Posiblemente rechazo no manejado: {} indefinido
Sé que esto está relacionado con este cambio , y la única solución es bastante simple al agregar el bloque .catch()
:
service.doSomething()
.then(function(result) {
var x = null;
var y = x.y;
//do something with the result
})
.catch(console.error);
Ahora nuevamente tengo lo que quiero:
TypeError: No se puede leer la propiedad ''y'' de null
Pero, ¿cómo obtener el mismo resultado (error más detallado) para toda la aplicación sin agregar el bloque .catch()
en cada lugar?
Probé la solución sugerida para deshabilitar esto agregando:
$qProvider.errorOnUnhandledRejections(false);
Pero con esto, la situación es aún peor: ¡no tengo NADA en la consola! El error se traga en alguna parte y no se registra en absoluto. No estoy seguro de que sea un problema con AngularJS 1.6 o con mi configuración.
¿Tiene alguna idea de cómo "restaurar" el comportamiento de registro de la versión 1.5.9?
EDITAR:
Agregando un controlador de errores personalizado:
.factory(''$exceptionHandler'', function($log) {
return function(exception, cause) {
$log.warn(exception, cause);
};
})
No ayuda en absoluto. En el controlador de errores ya recibo el error "envuelto".
Esto se ha solucionado con la corrección ($ q): agregue el rastreo a los rechazos de promesa no manejados: confirme 316f60f y la corrección se incluye en la versión v1.6.1 .
Hay otro caso, agregar un controlador finally()
a una promesa genera el error: http://plnkr.co/edit/eT834BkIEooAMvrVcLDe
Porque finally()
crea una nueva promesa y llama al resolutor en ella. (Rechazando un segundo en un caso de rechazo)
He puesto una solución en el plnkr pero no se ve muy bien.
La primera opción es simplemente ocultar un error con deshabilitar la errorOnUnhandledRejections
de errorOnUnhandledRejections
en $ qConfiguración del proveedor como se sugiere a Cengkuru Michael :
app.config([''$qProvider'', function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
}]);
PERO esto solo apagará el registro. El error en sí permanecerá
La mejor solución en este caso será: manejar un rechazo con el método .catch()
:
service.doSomething()
.then(function (response) {})
.catch(function (err) {});
Enlaces útiles:
Obtuve el mismo error de rechazo no manejado cuando una promesa rechazada no es manejada por angi-ui-router (ui-sref) usando ver1.6.1 angular. Esta función está habilitada de manera predeterminada.
Para cualquier persona que quiera una solución alternativa (aunque no se recomienda), puede silenciar globalmente los rechazos de promesa no manejados como este:
app.config([''$qProvider'', function ($qProvider) { $qProvider.errorOnUnhandledRejections(false); }]);
Resolví este error agregando un valor predeterminado en el bloque catch como:
service.doSomething()
.then(function(response) {
var x = null;
var y = x.y;
}).catch(function(error) {
var y = 0;
});
(Ten en cuenta que no soy un desarrollador angular experimentado)
Solucioné el mismo problema con la versión 1.6.1 al actualizar angular-ui-router a 0.3.2.
Tengo el problema incluso con la versión 1.6.1 en mi httpErrorInterceptor, por ejemplo, si mi API devuelve 404 tengo que intentar otra solicitud con otros datos ... así que en este caso solo rechazo la solicitud y arrojo el rechazo no manejado. error...
¡Instalo 1.5.9 y ahora no hay más errores!
errorOnUnhandledRejections (false); No fue una resolución para mí.
De hecho, es necesario que defina un controlador de excepciones ... sin embargo ... envuélvalo en una función de tiempo de espera: esto forzará el lanzamiento de la excepción / pila original.
Para que el error se muestre como un error en la consola web, como pretendía originalmente:
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;
})
};
});
Aquí está el truco del tiempo de espera: ¿Por qué no puedo lanzar dentro de un controlador Promise.catch?