Come verificare se una promessa $ q angolare è stata risolta


84

Capisco che in genere si allega semplicemente il codice di continuazione con una then()chiamata e il comportamento della catena quando si usano le promesse.

Tuttavia, desidero avviare una chiamata asincrona avvolta dalla promessa e quindi avviare separatamente una chiamata di 3 secondi in $timeout()modo da poter eseguire un'azione dell'interfaccia utente, SOLO SE la promessa originale non è stata ancora completata. (Prevedo che ciò accadrebbe solo su connessioni lente, dispositivi mobili su 3G, ecc.)

Data una promessa, posso verificare se è completa o meno senza bloccarla o attendere?


2
Ho aperto un problema su questo in angolare e ho ricevuto una risposta utile github.com/angular/angular.js/issues/8307#issuecomment-49903373
derekdreery

Risposte:


46

Immagino che questo sia stato aggiunto in una versione recente di Angular, ma ora sembra esserci un oggetto di stato $$ sulla promessa:

 var deferred = $q.defer();
 console.log(deferred.promise.$$state.status); // 0
 deferred.resolve();
 console.log(deferred.promise.$$state.status); //1 

Come notato nei commenti, questo non è raccomandato in quanto potrebbe non funzionare durante l'aggiornamento della versione Angular.


25
I documenti angolari dicono che le $$...proprietà non dovrebbero essere usate. Potrebbe essere rischioso durante l'aggiornamento a versioni più recenti di Angular ...
hgoebl

7
Peccato che Angular fornisca le sue variabili private su un piatto d'argento. :(
Jackson,


2
Ma ma ... Angular non ha implementato la inspectfunzione. Quindi niente succo per noi sviluppatori angolari. Il prototipo Promise semplicemente non ce l'ha.
Robert Koritnik,

36

Penso che la tua migliore opzione così com'è, (senza modificare la fonte Angular e inviare una richiesta pull) sia quella di mantenere un flag locale se la promessa è stata risolta. Reimpostalo ogni volta che imposti la promessa che ti interessa e contrassegnalo come completo nella then()promessa originale. Nella $timeout then()spunta il flag per sapere se la promessa originale si è ancora risolta oppure no.

Qualcosa come questo:

var promiseCompleted = false;
promise.then(function(){promiseCompleted=true;})
$timeout(...).then(function(){if(!promiseCompleted)doStuff()})

L'implementazione di Kris Kowal include altri metodi per controllare lo stato della promessa, ma sembra che l'implementazione di Angular $qpurtroppo non li includa.


9
Sarebbe meglio usare .finally () qui. Il codice fornito sopra contrassegnerà il flag promiseCompleted su true solo se è stato risolto correttamente.
Karanvir Kang

8

Non sembra possibile, come ha già detto @shaunhusain. Ma forse non è necessario:

// 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 forse meglio:

var tooSlow = $timeout(doStuff, 3000);
promise.always(tooSlow.cancel);

1

Ho avuto un problema simile in cui devo controllare se una promessa è stata restituita. Poiché la $watchfunzione di AngularJS registrerà una modifica durante il rendering della pagina anche se sia i valori nuovi che quelli vecchi non sono definiti, devo controllare se ci sono dati che vale la pena memorizzare nel mio modello esterno.

È sicuramente un trucco ma lo faccio:

$scope.$watch('userSelection', function() {
  if(promiseObject.hasOwnProperty("$$v"){
    userExportableState.selection = $scope.userSelection;
  }
};

So che $$vè una variabile interna utilizzata da AngularJS, ma è stata abbastanza affidabile come indicatore di una promessa risolta per noi. Chissà cosa succederà quando aggiorneremo ad AngularJS 1.2: - / Non vedo alcuna menzione di miglioramenti $qnella documentazione 1.2 ma forse qualcuno scriverà un servizio sostitutivo con un set di funzionalità migliore più vicino a Q.


Grazie, ma ci sono opzioni migliori rispetto all'utilizzo di membri "privati".
Jackson,

0

Non conosco il tuo scenario esatto, ma è più tipico impostare un timeout immediatamente dopo aver effettuato la chiamata asincrona (e aver generato la promessa).

Se l' setTimeout()istruzione si trova nello stesso thread dell'evento della chiamata asincrona, non è necessario preoccuparsi della possibilità di un effetto gara. Poiché javascript è strettamente a thread singolo, .then()è garantito che i callback della promessa si attivino in un thread di evento successivo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.