Jak sprawdzić, czy obietnica Angular $ q została rozwiązana

84

Rozumiem, że zazwyczaj wystarczy dołączyć kod kontynuacji z zachowaniem then()wywołania i łańcucha podczas korzystania z obietnic.

Chcę jednak rozpocząć asynchroniczne wywołanie zapakowane w obietnicę, a następnie osobno rozpocząć 3-sekundowe, $timeout()aby móc wykonać akcję interfejsu użytkownika, TYLKO JEŚLI pierwotna obietnica jeszcze się nie zakończyła. (Spodziewam się, że stanie się to tylko w przypadku wolnych połączeń, urządzeń mobilnych w sieci 3G itp.)

Czy po złożeniu obietnicy mogę sprawdzić, czy jest ona zakończona, czy nie, bez blokowania lub czekania?

blaster
źródło
2
Otworzyłem problem w tej sprawie w kątowej i otrzymałem pomocną odpowiedź github.com/angular/angular.js/issues/8307#issuecomment-49903373
derekdreery
możliwy duplikat stackoverflow.com/questions/27039771/ ...
mvermand

Odpowiedzi:

46

Wydaje mi się, że zostało to dodane w najnowszej wersji Angulara, ale wydaje się, że obecnie istnieje obiekt stanu $$ w obietnicy:

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

Jak zauważono w komentarzach, nie jest to zalecane, ponieważ może się zepsuć podczas aktualizacji wersji Angular.

parlament
źródło
25
Dokumentacja Angular twierdzi, że $$...właściwości nie powinny być używane. Może być ryzykowne podczas aktualizacji do nowszych wersji
Angulara
7
Szkoda, że ​​Angular udostępnia swoje prywatne zmienne na srebrnym talerzu. :(
Jackson
2
zobacz także: stackoverflow.com/questions/27039771/…
mvermand
2
Ale ale ... Angular nie zaimplementował tej inspectfunkcji. Więc nie ma soku dla nas, programistów Angular. Prototyp Promise po prostu go nie ma.
Robert Koritnik
36

Myślę, że najlepszą opcją w obecnej postaci (bez modyfikowania źródła Angular i wysyłania żądania ściągnięcia) jest zachowanie lokalnej flagi, jeśli obietnica została rozwiązana. Zresetuj ją za każdym razem, gdy konfigurujesz interesującą Cię obietnicę i oznacz ją jako ukończoną w then()pierwotnej obietnicy. w$timeout then() czeku flaga wiedzieć, czy oryginalna obietnica lub nie został jeszcze rozwiązany.

Coś takiego:

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

Implementacja Krisa Kowala zawiera inne metody sprawdzania stanu obietnicy, ale wydaje się, że implementacja $qAngulara niestety ich nie obejmuje.

shaunhusain
źródło
9
Lepiej byłoby użyć tutaj .finally (). Kod podany powyżej oznaczy flagę promiseCompleted na wartość true tylko wtedy, gdy zostanie pomyślnie rozwiązany.
Karanvir Kang
8

Wydaje się, że nie jest to możliwe, o czym wspomniał już @shaunhusain. Ale może nie jest to konieczne:

// 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);

a może lepiej:

var tooSlow = $timeout(doStuff, 3000);
promise.always(tooSlow.cancel);
Bergi
źródło
1

Miałem podobny problem, w którym muszę sprawdzić, czy obietnica wróciła. Ponieważ $watchfunkcja AngularJS zarejestruje zmianę podczas renderowania strony, nawet jeśli zarówno nowe, jak i stare wartości są niezdefiniowane, muszę sprawdzić, czy są jakieś dane, które warto przechowywać w moim modelu zewnętrznym.

To zdecydowanie hack, ale robię to:

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

Wiem, że $$vjest to zmienna wewnętrzna używana przez AngularJS, ale okazała się dla nas całkiem wiarygodna jako wskaźnik rozwiązanej obietnicy. Kto wie, co się stanie, kiedy zaktualizujemy AngularJS 1.2: - / Nie widzę żadnej wzmianki o ulepszeniach $qw dokumentacji 1.2, ale być może ktoś napisze usługę zastępczą z lepszym zestawem funkcji bliżej Q.

PatchCR
źródło
Dzięki, ale są lepsze opcje niż korzystanie z członków „prywatnych”.
Jackson
0

Nie znam twojego dokładnego scenariusza, ale bardziej typowe jest ustawienie limitu czasu natychmiast po wykonaniu wywołania asynchronicznego (i wygenerowaniu obietnicy).

Pod warunkiem, że setTimeout()instrukcja znajduje się w tym samym wątku zdarzenia, co wywołanie asynchroniczne, nie musisz się martwić o możliwość wystąpienia efektu wyścigu. Ponieważ javascript jest ściśle jednowątkowy, .then()wywołania zwrotne obietnicy z pewnością zostaną uruchomione w późniejszym wątku zdarzenia.

Burak-Burak
źródło