Czy musisz anulować subskrypcję połączeń HTTP Angular 2, aby zapobiec wyciekom pamięci?
fetchFilm(index) {
var sub = this._http.get(`http://example.com`)
.map(result => result.json())
.map(json => {
dispatch(this.receiveFilm(json));
})
.subscribe(e=>sub.unsubscribe());
...
angular
memory-leaks
rxjs
angular2-http
born2net
źródło
źródło
Odpowiedzi:
Więc odpowiedź brzmi nie, ty nie.
Ng2
sam to posprząta.Źródło usługi HTTP, ze źródła zaplecza Http XHR Angulara:
Zauważ, jak to działa
complete()
po uzyskaniu wyniku. Oznacza to, że faktycznie wypisuje się po zakończeniu. Więc nie musisz tego robić sam.Oto test sprawdzający poprawność:
Zgodnie z oczekiwaniami, możesz zobaczyć, że zawsze jest automatycznie anulowany po uzyskaniu wyniku i zakończeniu obserwowalnymi operatorami. Dzieje się to po przekroczeniu limitu czasu (# 3), dzięki czemu możemy sprawdzić status obserwowalnego, gdy wszystko zostanie wykonane i ukończone.
I wynik
Tak więc nie byłoby wycieku, ponieważ
Ng2
auto wypisuje się!Miło wspomnieć:
Observable
jest to podzielone na kategorie, ponieważfinite
w przeciwieństwie do tego,infinite
Observable
który jest nieskończonym strumieniem danych, może być emitowany jakclick
na przykład odbiornik DOM .DZIĘKI, @rubyboy za pomoc w tej sprawie.
źródło
O czym rozmawiacie!
OK, więc istnieją dwa powody, by zrezygnować z subskrypcji. Wydaje się, że nikt nie mówi dużo o bardzo ważnym drugim powodzie!
(W przypadku HTTP to faktycznie anuluje również żądanie w przeglądarce - więc nie będzie marnować czasu na czytanie odpowiedzi. Ale to właściwie pomijając mój główny punkt poniżej).
Trafność numeru 2 będzie zależeć od tego, co robi program obsługi subskrypcji:
Rozważ kilka przypadków:
1) Formularz logowania. Podaj nazwę użytkownika i hasło, a następnie kliknij „Zaloguj się”. Co jeśli serwer działa wolno i zdecydujesz się nacisnąć Escape, aby zamknąć okno dialogowe? Prawdopodobnie będziesz zakładać, że nie jesteś zalogowany, ale jeśli żądanie HTTP zwróciło się po naciśnięciu klawisza Escape, nadal będziesz wykonywać dowolną logikę. Może to spowodować przekierowanie na stronę konta, ustawienie niepożądanego pliku cookie logowania lub zmiennej tokena. Prawdopodobnie nie tego oczekiwał użytkownik.
2) Formularz „wyślij e-mail”.
Jeśli
subscribe
moduł obsługi funkcji „sendEmail” wywoła animację „Twój e-mail został wysłany”, przenieś Cię na inną stronę lub spróbujesz uzyskać dostęp do wszystkiego, co zostało usunięte, możesz uzyskać wyjątki lub niepożądane zachowanie.Uważaj również, aby nie zakładać, że
unsubscribe()
oznacza „anuluj”. Gdy wiadomość HTTP jest w locieunsubscribe()
, NIE anuluje żądania HTTP, jeśli już dotarło do twojego serwera. To tylko anuluje odpowiedź, która do ciebie wróci. I e-mail prawdopodobnie zostanie wysłany.Jeśli utworzysz subskrypcję, aby wysyłać wiadomości e-mail bezpośrednio w składniku interfejsu użytkownika, prawdopodobnie zechcesz zrezygnować z subskrypcji, ale jeśli wiadomość e-mail jest wysyłana przez usługę scentralizowaną bez interfejsu użytkownika, prawdopodobnie nie będzie to konieczne.
3) Element kątowy, który jest zniszczony / zamknięty. Wszelkie obserwowalne http, które nadal działają w tym czasie, zakończą się i uruchomią swoją logikę, chyba że anulujesz subskrypcję
onDestroy()
. To, czy konsekwencje będą trywialne, czy nie, zależy od tego, co robisz w module obsługi subskrypcji. Jeśli spróbujesz zaktualizować coś, co już nie istnieje, może pojawić się błąd.Czasami możesz wykonać pewne działania, które chcesz, jeśli składnik zostanie usunięty, a niektóre nie. Na przykład może masz dźwięk „szumu” dla wysłanej wiadomości e-mail. Prawdopodobnie chciałbyś, aby to grało, nawet jeśli komponent był zamknięty, ale jeśli spróbujesz uruchomić animację na komponencie, zakończy się niepowodzeniem. W takim przypadku rozwiązaniem może być dodatkowa logika warunkowa w ramach subskrypcji - i NIE chcesz zrezygnować z subskrypcji obserwowalnego http.
Więc w odpowiedzi na aktualne pytanie, nie musisz tego robić, aby uniknąć wycieków pamięci. Ale musisz to zrobić (często), aby uniknąć niepożądanych efektów ubocznych uruchamianych przez kod, który może zgłaszać wyjątki lub uszkodzić stan aplikacji.
Wskazówka:
Subscription
Zawieraclosed
właściwość logiczną, która może być przydatna w zaawansowanych przypadkach. W przypadku HTTP zostanie to ustawione po zakończeniu. W Angular może być użyteczne w niektórych sytuacjach, aby ustawić_isDestroyed
właściwość, wngDestroy
której może być sprawdzony przezsubscribe
program obsługi.Wskazówka 2: W przypadku obsługi wielu subskrypcji możesz utworzyć obiekt ad-hoc
new Subscription()
iadd(...)
wszelkie inne subskrypcje do niego - więc anulowanie subskrypcji głównej spowoduje anulowanie subskrypcji również wszystkich dodanych subskrypcji.źródło
Wywołanie
unsubscribe
metody polega raczej na anulowaniu trwającego żądania HTTP, ponieważ metoda ta wywołuje tęabort
na bazowym obiekcie XHR i usuwa detektory zdarzeń obciążenia i błędów:To powiedziawszy,
unsubscribe
usuwa słuchaczy ... Może to być dobry pomysł, ale nie sądzę, że jest to konieczne do pojedynczej prośby ;-)Mam nadzieję, że ci to pomoże, Thierry
źródło
y = x.subscribe((x)=>data = x);
wtedy zmiana danych wejściowych użytkownika ix.subscribe((x)=>cachlist[n] = x); y.unsubscribe()
hej, wykorzystałeś nasze zasoby serwerowe, wygrałem wyrzucę cię ..... w innym scenariuszu: po prostu zadzwońy.stop()
wyrzuć wszystkoRezygnacja z subskrypcji jest NIEZBĘDNA, jeśli chcesz deterministycznego zachowania na wszystkich prędkościach sieci.
Wyobraź sobie, że komponent A jest renderowany na karcie - Kliknij przycisk, aby wysłać żądanie „GET”. Odpowiedź trwa 200 ms. Tak więc możesz bezpiecznie zamknąć kartę w dowolnym momencie, wiedząc, że urządzenie będzie szybsze niż Ty, a odpowiedź HTTP zostanie przetworzona i zakończy się przed zamknięciem karty i zniszczeniem komponentu A.
Co powiesz na bardzo powolną sieć? Klikasz przycisk, żądanie „GET” trwa 10 sekund, aby otrzymać odpowiedź, ale po 5 sekundach czekania zdecydujesz się zamknąć kartę. Spowoduje to zniszczenie składnika A, który zostanie później wyrzucony. Poczekaj minutę! , nie anulowaliśmy subskrypcji - teraz 5 sekund później wraca odpowiedź i logika w zniszczonym komponencie zostanie wykonana. To wykonanie jest teraz rozważane
out-of-context
i może spowodować wiele rzeczy, w tym bardzo niską wydajność.Dlatego najlepszą praktyką jest używanie
takeUntil()
i anulowanie subskrypcji wywołań http, gdy składnik zostanie zniszczony.źródło
BehaviorSubject()
zamiast zadzwonić i właśniecomplete()
wngOnDestroy()
?BehaviourSubject
być inaczej?Również z nowym modułem HttpClient pozostaje takie samo zachowanie
źródło
Nie należy wypisywać się z obserwowalnych elementów, które kończą się automatycznie (np. HTTP, połączenia). Ale konieczne jest zrezygnowanie z nieskończonej ilości obserwowalnych obiektów, takich jak
Observable.timer()
.źródło
Po chwili testowania przeczytałem dokumentację i kod źródłowy HttpClient.
HttpClient:
https://github.com/angular/angular/blob/master/packages/common/http/src/client.tsHttpXhrBackend :
https://github.com/angular/angular/blob/master/packages/common/http/src/xhr.tsHttpClientModule
: https://indepth.dev/exploring-the-httpclientmodule-in-angular/Angular Univeristy: https://blog.angular-university.io/angular-http/
A odpowiedź na cały problem „czy muszę się wypisać”?
To zależy. Połączenie HTTP Nieszczelności pamięci nie stanowią problemu. Problemy dotyczą logiki funkcji zwrotnych.
Na przykład: Routing lub Login.
Jeśli Twoje połączenie jest logowaniem, nie musisz „anulować subskrypcji”, ale musisz się upewnić, że jeśli użytkownik opuści stronę, odpowiednio zareagujesz na nieobecność użytkownika.
Od irytujących po niebezpieczne
Teraz wyobraź sobie, że sieć działa wolniej niż zwykle, połączenie trwa dłużej 5 sekund, a użytkownik opuszcza widok logowania i przechodzi do „widoku wsparcia”.
Składnik może nie być aktywny, ale subskrypcja. W przypadku odpowiedzi użytkownik zostanie nagle przekierowany (w zależności od implementacji handleResponse ()).
To nie jest dobre.
Wyobraź sobie również, że użytkownik opuszcza komputer, wierząc, że nie jest jeszcze zalogowany. Ale logika loguje użytkownika, teraz masz problem z bezpieczeństwem.
Co możesz zrobić BEZ rezygnacji z subskrypcji?
Uzależnij połączenie od aktualnego stanu widoku:
Użytkownik,
.pipe(takeWhile(value => this.isActive))
aby upewnić się, że odpowiedź jest obsługiwana tylko wtedy, gdy widok jest aktywny.Ale skąd masz pewność, że subskrypcja nie powoduje wycieków pamięci?
Możesz się zalogować, jeśli zastosowano „teardownLogic”.
TeardownLogic subskrypcji zostanie wywołany, gdy subskrypcja będzie pusta lub anulowana.
Nie musisz rezygnować z subskrypcji. Powinieneś wiedzieć, czy w Twojej logice występują problemy, które mogą powodować problemy z subskrypcją. I zaopiekuj się nimi. W większości przypadków nie będzie to problemem, ale szczególnie przy krytycznych zadaniach, takich jak autoryzacja, powinieneś zadbać o nieoczekiwane zachowanie, zastępując je „anulowaniem subskrypcji” lub inną logiką, taką jak piping lub warunkowe funkcje zwrotne.
dlaczego nie zawsze zrezygnować z subskrypcji?
Wyobraź sobie, że składasz żądanie sprzedaży lub postu Serwer odbiera wiadomość w obu kierunkach, tylko odpowiedź trwa chwilę. Anulowanie subskrypcji nie spowoduje cofnięcia postu ani umieszczenia. Ale gdy anulujesz subskrypcję, nie będziesz mieć możliwości obsłużenia odpowiedzi lub poinformowania użytkownika, na przykład za pomocą okna dialogowego lub wiadomości / wiadomości itp.
Co powoduje, że Użytkownik uważa, że żądanie umieszczenia / wysłania nie zostało wykonane.
Więc to zależy. To Twoja decyzja projektowa, jak poradzić sobie z takimi problemami.
źródło
Zdecydowanie powinieneś przeczytać ten artykuł. Pokazuje, dlaczego zawsze powinieneś wypisać się nawet z http .
Aktualizacja
Powyższa afirmacja wydaje się być prawdą, ale w każdym razie, kiedy odpowiedź wróci, subskrypcja HTTP i tak zostanie zniszczona
źródło
Obserwowalne RxJS są w zasadzie powiązane i działają odpowiednio, jeśli je subskrybujesz. Kiedy tworzymy obserwowalny ruch i wykonujemy go, obserwowalny automatycznie zostaje zamknięty i anulowany.
Działają w ten sam sposób, co obserwatorzy, ale w zupełnie innej kolejności. Lepszą praktyką jest anulowanie ich, gdy komponent się niszczy. Następnie możemy to zrobić np. this. $ manageSubscription.unsubscibe ()
Jeśli stworzyliśmy obserwowalną składnię, taką jak poniżej, taką jak
** zwróć nowy Obserwowalny ((obserwator) => {** // To sprawia, że można go zaobserwować w stanie zimnym ** observer.complete () **}) **
źródło