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?
Odpowiedzi:
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.
źródło
$$...
właściwości nie powinny być używane. Może być ryzykowne podczas aktualizacji do nowszych wersjiinspect
funkcji. Więc nie ma soku dla nas, programistów Angular. Prototyp Promise po prostu go nie ma.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
$q
Angulara niestety ich nie obejmuje.źródło
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);
źródło
Miałem podobny problem, w którym muszę sprawdzić, czy obietnica wróciła. Ponieważ
$watch
funkcja 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
$$v
jest 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$q
w dokumentacji 1.2, ale być może ktoś napisze usługę zastępczą z lepszym zestawem funkcji bliżej Q.źródło
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.źródło