2013-07-26 16 views
78

Capisco che in genere si dovrebbe solo allegare il codice di continuazione con un comportamento di chiamata e catena then() quando si utilizzano le promesse.

Tuttavia, voglio dare il via ad una chiamata asincrona promessa e poi avviare separatamente uno $timeout() di 3 secondi in modo da poter eseguire un'azione dell'interfaccia utente, SOLO SE la promessa originale non è ancora stata completata. (Prevedo che ciò accada solo su connessioni lente, dispositivi mobili su 3G, ecc.)

Data una promessa, posso verificare se è completa o meno senza blocco o in attesa?

+2

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

+0

possibile duplicato di http://stackoverflow.com/questions/27039771/q-js-è-possibile-sapere-se-una-promessa-ha-risolto-respinto-o-non – mvermand

risposta

36

Penso che l'opzione migliore così com'è (senza modificare la fonte Angolare e inviare una richiesta di pull) sia di mantenere una bandiera locale se la promessa è stata risolta. Resettalo ogni volta che imposti la promessa che ti interessa e contrassegnalo come completo nello then() per la promessa originale. Nel $timeoutthen() controlla la bandiera per sapere se la promessa originale è stata risolta o meno.

Qualcosa di simile a questo:

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

implementazione di Kris Kowal include altri metodi per la verifica dello stato della promessa ma sembra implementazione di angolare di $q purtroppo non include questi.

+7

Sarebbe meglio usare .finalmente() qui. Il codice sopra riportato segnerà il flag promiseCompleted solo se è stato risolto correttamente. –

+0

Un buon punto, finalmente è probabilmente meglio – shaunhusain

0

Non conosco lo scenario esatto ma è più tipico mettere un timeout sul posto immediatamente dopo aver effettuato la chiamata asincrona (e generando la promessa).

Se l'istruzione setTimeout() si trova nello stesso thread di evento della chiamata asincrona, non è necessario preoccuparsi della possibilità di un effetto di gara. Siccome javascript è strettamente single threaded, i callback .then() della promessa sono garantiti per l'attivazione in un thread evento successivo.

+0

Quindi il tuo codice si rompe quando i browser iniziano ad implementare javascript asincroni come 'node'. –

8

Non sembra possibile, come 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 ho bisogno di controllare se una promessa è tornato. Poiché la funzione $watch di AngularJS registrerà una modifica durante il rendering della pagina anche se i valori vecchi e nuovi non sono definiti, devo verificare se ci sono dati che vale la pena archiviare nel mio modello esterno.

E 'sicuramente un hack, ma faccio questo:

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

so che $$v è una variabile interna utilizzata da AngularJS, ma è stato abbastanza affidabile come indicatore di una promessa risolto per noi. Chissà cosa succederà quando eseguiremo l'upgrade ad AngularJS 1.2: -/Non vedo alcuna menzione dei miglioramenti a $q nei documenti 1.2, ma forse qualcuno scriverà un servizio di sostituzione con un set di funzionalità migliore più vicino a Q.

+0

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

45

Credo che questo è stato aggiunto in una versione recente di angolare, ma sembra che ci sia ormai 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 rompersi quando si aggiorna la versione angolare.

+23

I documenti angolari dicono che le proprietà '$$ ...' non dovrebbero essere usate. Potrebbe essere rischioso quando si aggiorna a versioni più recenti di Angular ... – hgoebl

+7

Pessimo Angular fornisce le sue variabili private su un piatto d'argento. :( – Jackson

+2

vedi anche: http://stackoverflow.com/questions/27039771/q-js-is-it-possible-to-know-if-a-promise-has-resolved-rejected-or-not – mvermand

Problemi correlati