RxJS 7 has shipped! For us Angular developers, it unfortunately did not ship in time for Angular 12.
I've summarized key takeaways from Ben Lesh’s talk from RxJS Live Asia and his slides below. Lesh is a member of the RxJS core team and formerly worked at Google on the Angular team.
Big Feature: Smaller Bundle Sizes
Lesh said while RxJS 7 was “a bit faster,” the big improvement for the new version is its bundle size. RxJS 7 is 53% the size of RxJS 6. If your app used every operator in version 6, that would require 52 KB, but the same thing in RxJS 7 requires just 19 KB.
“This was done via a refactor, a hundred-point improvement of going around and individually moving around code, keeping the same tests, keeping the same code, and moving things around slowly but surely until we got to a place where we could see daylight and we were able to refactor larger portions of the code,” Lesh said in his talk.
See this chart of operator sizes in RxJS 6:
And this chart of the same operator sizes in RxJS 7:
Consolidating Sharing operators
Lesh’s talk includes a long discussion about how many ways RxJS lets you share a stream (multicast
, shareReplay
, refCount
, etc).
RxJS 7 deprecates multicast
, publish
, publishReplay
, publishLast
, and refCount
. shareReplay
was too popular to deprecate in 7, but Lesh said it's next because it is "full of footguns.” Long term, the only sharing operators will be share
, connect
and connectable
. He recommends moving to share
now.
share
is picking up some new features as the single solution operator. It takes an optional config object as a parameter, where you can define custom behavior for the stream.
share({
connector: () => new ReplaySubject(),
resetOnRefCountZero: true,
resetOnComplete: true,
resetOnError: true
})
Better TypeScript Typings
RxJS 7 requires TypeScript 4.2, Lesh said, because it contains features that enable more accurate, stricter types. One example he gave in his slides involved Subject
:
// allowed in RxJS 6, errors in 7 because next() must be called with a number
const subject = new Subject<number>()
subject.next()
For teams that are unable to upgrade to TypeScript 4.2, Lesh recommended staying on RxJS 6, which the RxJS team will continue to support.
toPromise() Deprecated
The problem with toPromise()
, Lesh explained, was that it didn't make sense with Observables. Should a promise created by toPromise()
resolve with the first or last value emitted from the source Observable?
So, toPromise()
is deprecated in favor of lastValueFrom()
and firstValueFrom()
. These new functions still convert Observables to Promises, but in a way that clarifies that value the Promise will resolve with.
const source = from([1, 2])
const firstVal = await firstValueFrom(source)
console.log(firstVal) // 1
const lastVal = await lastValueFrom(source)
console.log(lastVal) // 2
If an Observable completes without emitting a value, the Promise created by lastValueFrom
or firstValueFromrejects
. If that is not desired behavior, you can configure the new Promise to resolve with a defaultValue.
const emptyVal = await firstValueFrom(source, { defaultValue: 'empty' })
console.log(emptyVal) // 'empty'
AsyncIterable support
Anywhere you can pass an Observable, RxJS 7 also lets you pass an AsyncIterable.
async function* ticket(delay: number) {
let n = 0;
while (true) {
await sleep(delay);
yield n;
}
}
Other Updates
- finalize()
operators now run in the order in which they are written in pipe()
. In contrast, RxJS 6 ran them in reverse.
- subscription.add(someSubscription)
now returns void so people will stop writing add()
chains, which Lesh says never worked.
// add() returns void, cannot be chained
subscription
.add(subOne)
.add(subTwo) // errors
- animationFrames()
creates Observables to do animation logic reactively
- switchScan()
operator, aka switchMap
with an accumulator
- throwError()
requires a callback, not an error, as the error captures the current stack at the moment of its creation
Your with
Is My Command
- combineLatest
operator renamed to combineLatestWith
- merge
operator renamed to mergeWith
- zip
operator renamed to zipWith
- race
operator renamed to raceWith
- concat
operator renamed to concatWith
Bitovi Recommendations for Migrating to RxJS 7
If your project can be upgraded to RxJS 7, we would recommend doing so. The speed and bundle size improvements offer tangible, immediate benefits to end users.
Important points to remember:
- Replace your toPromise
calls with firstValueFrom
and lastValueFrom
- Replace your shareReplay
calls with share
- Stop using .add
chains to manage your subscriptions. Lesh recommends takeUntil
If you need help upgrading to RxJS 7, fill out our form. Bitovi has a team of Angular and RxJS experts who can help your team.