DevCezz

Programistyczny blog dla Ciebie

Czy zawsze trzeba odsubskrybować wszystkie Observable w Angular?
Angular

Czy zawsze trzeba odsubskrybować wszystkie Observable w Angular?

Podczas tworzenia aplikacji Barents Watch zastanawiałem się czy zawsze trzeba odsubskrybować wszystkie Observable, gdy kończymy pracę z danym komponentem Angulara. Okazało się, że według niektórych programistów niekoniecznie. Wyjątek ma dotyczyć m.in. serwisu HttpClient, który ma w sobie mechanizm kończenia subskrypcji po wykonaniu zapytania. Przekonajmy się jak to naprawdę wygląda opierając się o wypowiedzi znalezione w Internecie.

Obóz otwocki

Szukając odpowiedzi na główne pytanie postawione przed tym artykułem napotkałem takie oto komentarze deweloperów na temat subskrybowania przez HttpClient. Na StackOverflow jedna z wypowiedzi na ten moment zdobyła aż 312 potwierdzeń, że była przydatna. Jej autor przedstawia w niej taki fragment kodu:

Notice how it runs the complete() after getting the result. This means it actually unsubscribes on completion. So you don’t need to do it yourself.

Oraz przy okazji podaje on przykład potwierdzający jego uzasadnienie. Idąc dalej możemy zajrzeć do oficjalnej dokumentacji Angulara. W niej znajdziemy takie zdanie:

In general, an observable can return multiple values over time. An observable from HttpClient always emits a single value and then completes, never to emit again.

Gdy skorzystamy z HttpClient to zwrócona zostanie pojedyncza wartość, a później Observable się zakończy i nigdy nie będzie już wyemitowana kolejna wartość. Oczywiście nie ma nigdzie informacji o tym, że nie trzeba odsubskrybować danego wywołania, bo skoro wszystko automatycznie się zadzieje to nie ma takiej konieczności. Szukając kolejnych potwierdzeń napotykamy blog Luka O, na którym znajduje się wpis o tytule Do we need to unsubscribe HTTP client in Angular?. Dokładnie to czego potrzebowaliśmy! Natomiast po lekturze dochodzimy do wniosku, że to te same argumenty co w wątku ze StackOverflow. Dochodzi tylko jeszcze jedna kwestia.

The same case goes for Subject, BehaviourSubject, and EventEmitter. They all have complete() method, so if you call that method, even if you had 100 subscriptions, they will all unsubscribed automatically.

Autor informuje, że ten sam mechanizm ma zastosowanie w Subject, BehaviourSubject i EventEmitter. W tej kwestii akurat jestem laikiem, ale grzebiąc dalej znajdziemy potwierdzenie w tym wpisie. Tylko trzeba mieć na uwadze, że wtedy musimy sami zadbać o wywołanie metody complete w odpowiednim momencie. No dobrze, a co na to drugi obóz?

Obóz falenicki

Kolejny wpis w tym samym wątku na StackOverflow, który został przytoczony na początku poprzedniej sekcji, zaczyna się takim nagłówkiem: What are you people talking about!!!. Autor od razu przytacza dwa powody, dla których powinno się odsubskrybować każdy Observable.

  1. Czyszczenie zasobów – w przypadku klienta HTTP jest to nie istotne, ponieważ on sam automatycznie po sobie sprząta
  2. Powstrzymanie wywołania obsługi metody subscribe

Następnie podaje 3 przykłady, dla których nie został odsubskrybowany Observable dla HttpClient i jakie to miało konsekwencje. Na koniec swoje stanowisko uzasadnia w taki sposób, że nie robiąc nic z tym fantem chronimy się tylko przed wyciekiem pamięci. Natomiast jesteśmy narażeni na efekty uboczne, które mogą wyrzucić wyjątek lub nawet zepsuć działanie naszej aplikacji.

Szukając dalszych zwolenników tego obozu natrafiamy na użytkownika Reactive Fox z portalu Medium. Jego wpis Why you HAVE to unsubscribe from Observable? pokazuje kilka ciekawych przypadków mówiących o tym dlaczego zawsze odsubskrybować Observable. Wśród nich znajdziemy przykłady dla HttpClient, gdzie przedstawiony został wyciek pamięci oraz niekończący się strumień zapytań HTTP (ekstremalny przypadek, ale możliwy do spełnienia). Wychodzi na to, że takie sytuacje też są możliwe.

Na StackOverflow znajdziemy kolejne potwierdzenie w tej wypowiedzi oraz tej, że warto kończyć nawet samokończące się subskrypcje. Jeśli jednak chcielibyśmy zobrazować sobie istnienie tego problemu oraz jego rozwiązanie to zapraszam na tą stronę do sekcje „Abort HTTP Request To Avoid Unwanted calls„. Tutaj na prostym przykładzie od początku do końca zostało zaprezentowane jak sytuacja wygląda w praktyce (nawet w formie graficznej).

Podsumowanie

Jak widać w swoim życiu zawodowym możesz spotkać się z dwoma różnymi podejściami. Ja osobiście po bliższym zapoznaniu się z tym tematem uważam, że lepiej być nadgorliwym i faktycznie ręcznie kończyć każdą subskrypcje, nawet gdy wszystko za nas robi automat. Przypadki prezentujące ekstremalne sytuacje przemawiają do mnie chociaż pewnie ich wystąpienie nie jest zbyt częste. Jednak po co być niemiło zaskoczonym jak możemy zawczasu się przed tym zabezpieczyć i spać spokojnie.

Podziel się tym z innymi!