Nieodzownym elementem Angulara jest reaktwyność, a wraz z nią RxJS, który niedawno miał debiut swojej siódmej już wersji. Angular w wersji 12.2 rozpoczął wsparcie tej wersji RxJS, przyjrzyjmy się zatem czego możemy się spodziewać.
1. Mniejszy bundle size
Pierwszym usprawnieniem jest mniejszy bundle size. RxJS 7 jest mniejszy o 47% od swojego poprzednika. Jeżeli twoja aplikacja używała wszystkich operatorów z wersji 6, co wymagałoby 52 KB, w wersji 7 będzie to tylko 19 KB. Mogłoby się wydawać, że nie jest to dużo, ale dla użytkownika mobilnego z wolnym połączeniem internetowym każdy KB ma znaczenie.
2. Lepsze typowanie – najnowszy Typescript
RxJS 7 wymaga Typescript co najmniej w wersji 4.2, który dostarcza znaczne usprawnienia w kontekście typowania. Spójrzmy tylko na poniższe przykłady:
1 2 3 4 5 6 7 8 9 |
// dozwolone w RxJS 6, błąd w 7 ponieważ next() musi być wywołane z typem number const subject = new Subject<number>() subject.next() // teraz typ zwracanej wartości będzie Observable<Date>, uprzednio był to Observable<undefined>. of(new Date(), null, undefined) .pipe(filter(Boolean)) .subscribe(); |
3. Deprecate toPromise()
Operator toPromise został oznaczony jako deprecated i zostanie usunięty w V8. W zamian otrzymujemy dwa nowe operatory lastValueFrom() i firstValueFrom(). Jak wskazuje nazwa, firstValueFrom zwraca pierwszą wartością strumienia, a lastValueFrom zwraca ostatnią wartość z obserwowanego strumienia. Jeśli nie zostaną wyemitowane żadne wartości, zostanie zgłoszony błąd, w przeciwieństwie do toPromise, który rozwiązuje się z wartością undefined. Jeżeli chcemy uniknąć błędu w przypadku braku emisji, możemy zdefiniować wartość domyślną.
1 2 3 4 5 6 7 8 9 10 11 |
const source = from([1, 2]) const firstVal = await firstValueFrom(source) console.log(firstVal) // 1 const lastVal = await lastValueFrom(source) console.log(lastVal) // 2 // definiowanie wartości domyślnej const firstVal = await firstValueFrom(source, { defaultValue: 'empty' } ) |
4. Zmiana nazwy operatorów
- combineLatest zmieniony na combineLatestWith
- merge zmieniony na mergeWith
- zip zmieniony na zipWith
- race zmieniony na raceWith
- concat zmieniony na concatWith
Stare operatory zostaną całkowicie usunięte, z następnym major releasem.
5. Uniemożliwienie łączenia subskrybcji przy wykorzystaniu subscrption.add()
subscritption.add() było używane do łączenia ze sobą wielu subskrybcji, tak żebyśmy mogli odsubkrybować się od wszystkich za jednym razem. Niestety jak sam twórca potwierdza, takie podejście jest błędne i może prowadzić do wielu nieoczekiwanych zachowań w kontekście odsubkrybowywania się (źródło). Od teraz subscription.add() zwraca void, a sam twórca RxJS zaleca m.in. używanie operatora takeUntil.
6. Operator retry z parametrem resetOnSuccess
Uprzednio parametr operatora retry nie był resetowany ‘onSuccess’. Obecnie uzyskujemy opcję, która pozwoli skonfigurować takie zachowanie.
1 2 3 4 |
retry({ count: 1, resetOnSuccess: true }) |
7. Duże zmiany w obrębie “Sharing operators”
Nastepujące operatory zostały oznaczone jako deprecated – multicast, publish, publishReplay, publishLast, and refCount. W planach było również pozbycie się operatora shareReplay, aczkolwiek na ten moment ten cieszy się bardzo dużą popularnością wśród programistów i pozostał w kolejnej wersji RxJS. Natomiast trzeba spodziewać się, że w przyszłości on również dołączy do wyżej wymienionych operatorów. W dłużej perspektywie pozostaną operatory share, connect oraz connectable. Na dzień dzisiejszy rekomendowane jest przenoszenie się na operator share. W wersji 7 zyskuje on kilka dodatkowych parametrów konfiguracyjnych, gdzie możemy zdefiniować niestandardowe zachowanie dla naszego strumienia.
1 2 3 4 5 6 |
share({ connector: () => new ReplaySubject(), resetOnRefCountZero: true, resetOnComplete: true, resetOnError: true }) |
Podsumowanie
To tylko wybrane nowości wchodzące w życie wraz z RxJS 7. Możesz przeczytać więcej o aktualizacji pod następującymi linkami:
- Oficjalna prezentacja RxJS 7 (wystąpienie + slajdy)
- Change summary
- Medium
- inDepth
Daj znać w komentarzu, która zmiana jest dla Ciebie najistotniejsza i dlaczego 😉
W podtytule „6. Operator retry z parametrem retryOnSuccess” chodziło o „resetOnSuccess”?
Tak, wielkie dzięki za wyłapanie błędu 🙂
dzięki za artykuł! przydał się przy przesiadce na nowego rxjs w projekcie 😉
jednak natrafiłem na pewien problem z nowym operatorem, może byłbyś w stanie podpowiedzieć o co może chodzić.
deklaruje zmienną w taki sposób
private observable$: Observable = of(5);
następnie w metodzie mam taki kod
await firstValueFrom(this.observable$);
powoduje to błąd tslinta o treści „Unsafe call of an
any
typed value.(@typescript-eslint/no-unsafe-call)”nie wiem skąd bierze any w tym miejscu i strasznie mnie to frustruje
private observable$: Observable = of(5); – umknęło mi, typ observable też jest określony