Cómo comprobar si se resuelve una promesa de $ q angular

84

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?

desintegrador
fuente
2
Abrí un problema sobre esto en angular y obtuve una respuesta útil github.com/angular/angular.js/issues/8307#issuecomment-49903373
derekdreery
posible duplicado de stackoverflow.com/questions/27039771/…
mvermand

Respuestas:

46

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.

parlamento
fuente
25
Los documentos de Angular dicen que las $$...propiedades no deben usarse. Podría ser arriesgado al actualizar a versiones más nuevas de Angular ...
hgoebl
7
Lástima que Angular proporcione sus variables privadas en bandeja de plata. :(
Jackson
2
ver también: stackoverflow.com/questions/27039771/…
mvermand
2
Pero pero ... Angular no implementó la inspectfunción. Así que no hay jugo para nosotros, desarrolladores de Angular. El prototipo de Promise simplemente no lo tiene.
Robert Koritnik
36

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 $qdesafortunadamente no los incluye.

Shaunhusain
fuente
9
Sería mejor usar .finally () aquí. El código proporcionado anteriormente solo marcará el indicador promiseCompleted como verdadero si se resolvió correctamente.
Karanvir Kang
8

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);
Bergi
fuente
1

Tuve un problema similar en el que necesito verificar si se ha devuelto una promesa. Debido a que la $watchfunció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 $$ves 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 $qen 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.

PatchCR
fuente
Gracias, pero hay mejores opciones que usar miembros "privados".
Jackson
0

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.

Remolacha-Remolacha
fuente