Entiendo que normalmente uno solo adjuntaría un código de continuación con una then()
llamada y un comportamiento en cadena al usar promesas.
Sin embargo, quiero iniciar una llamada asincrónica envuelta en promesas y luego iniciar por separado una llamada de 3 segundos $timeout()
para poder realizar una acción de IU, SOLO SI la promesa original aún no se ha completado. (Anticipo que esto solo sucedería en conexiones lentas, dispositivos móviles en 3G, etc.)
Dada una promesa, ¿puedo verificar si está completa o no sin bloquear o esperar?
Respuestas:
Supongo que esto se agregó en una versión reciente de Angular, pero parece que ahora hay un objeto de estado $$ en la promesa:
var deferred = $q.defer(); console.log(deferred.promise.$$state.status); // 0 deferred.resolve(); console.log(deferred.promise.$$state.status); //1
Como se señaló en los comentarios, esto no se recomienda, ya que podría romperse al actualizar su versión Angular.
fuente
$$...
propiedades no deben usarse. Podría ser arriesgado al actualizar a versiones más nuevas de Angular ...inspect
función. Así que no hay jugo para nosotros, desarrolladores de Angular. El prototipo de Promise simplemente no lo tiene.Creo que su mejor opción tal como está (sin modificar la fuente angular y enviar una solicitud de extracción) es mantener una bandera local si la promesa se ha resuelto. Restablezca cada vez que configure la promesa que le interesa y márquela como completa en la
then()
promesa original. En el$timeout
then()
marque la bandera para saber si la promesa original se ha resuelto todavía o no.Algo como esto:
var promiseCompleted = false; promise.then(function(){promiseCompleted=true;}) $timeout(...).then(function(){if(!promiseCompleted)doStuff()})
La implementación de Kris Kowal incluye otros métodos para verificar el estado de la promesa, pero parece que la implementación de Angular
$q
desafortunadamente no los incluye.fuente
No parece posible, como ya mencionó @shaunhusain. Pero quizás no sea necesario:
// shows stuff from 3s ahead to promise completetion, // or does and undoes it in one step if promise completes before $q.all(promise, $timeout(doStuff, 3000)).then(undoStuff);
o tal vez mejor:
var tooSlow = $timeout(doStuff, 3000); promise.always(tooSlow.cancel);
fuente
Tuve un problema similar en el que necesito verificar si se ha devuelto una promesa. Debido a que la
$watch
función de AngularJS registrará un cambio al renderizar la página, incluso si los valores nuevos y antiguos no están definidos, tengo que verificar si hay algún dato que valga la pena almacenar en mi modelo externo.Definitivamente es un truco, pero hago esto:
$scope.$watch('userSelection', function() { if(promiseObject.hasOwnProperty("$$v"){ userExportableState.selection = $scope.userSelection; } };
Sé que
$$v
es una variable interna utilizada por AngularJS, pero ha sido bastante confiable como indicador de una promesa resuelta para nosotros. Quién sabe qué pasará cuando actualicemos a AngularJS 1.2: - / No veo ninguna mención de mejoras$q
en los documentos 1.2, pero tal vez alguien escriba un servicio de reemplazo con un conjunto de características mejor más cercano a Q.fuente
No conozco su escenario exacto, pero es más típico establecer un tiempo de espera inmediatamente después de realizar la llamada asincrónica (y generar la promesa).
Siempre que la
setTimeout()
declaración esté en el mismo hilo de eventos que la llamada asíncrona, no debe preocuparse por la posibilidad de un efecto de carrera. Como javascript es estrictamente de un solo subproceso,.then()
se garantiza que las devoluciones de llamada de la promesa se activen en un subproceso de evento posterior.fuente