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.