The State of RxJS – Ben Lesh at Ngconf

RxJS core team member and lead Ben Lesh presented at ng-conf the upcoming features for RxJS 7.

Lesh started by reminding the audience of the RxJS goals. RxJS is a utility library that has been steadily growing in popularity, as a result of reactive programming paradigms becoming more commonplace. As an utility library that can be used in many different contexts and frameworks, RxJS strives to be stable and dependable, constantly improve developer experience, and optimize its bundle size.

Stability, reliability, and maintainability are characteristics that are highly desirable in enterprise software. To further progress in that direction, Lesh mentioned a few ongoing initiatives.

The RxJS team instituted a process that ensures the absence of breaking changes between patch releases and a smooth migration path for RxJS 8 and above. RxJS partnered with Google so that the latest versions of RxJS may run on google3 (Google mono-repository) to surface any occurring bugs and breaking changes. Lesh explained:

[Moshe Kolodney helped set up a task force] inside of Google that puts the latest version of RxJS into google3 […] and runs it against all of their build targets — thousands and thousands of build targets, tons of apps using RxJS just in every way you can imagine, to see what breaks. They [then] report to us and let us know what breaks and we work with them to resolve those issues well before you would ever see a published release on NPM

RxJS 7 is also seeking to take advantage of newer versions of TypeScript to provide better type inference to the library users. Lesh gave the example of N-arguments methods for which type inference would work up to the 9 arguments that are encoded in the RxJS method type definition files:

Before we might have had an upper bound limit of like eight or nine values and then after that we could not infer the type anymore. Now, you can go up to any number of values and TypeScript will figure it out.

The RxJS team also fixed incorrect types. The following code illustrates an example:

async function test(){ const names$: Observable <string[]> = getNames(); const names = await names$.toPromise();        console.log(names); } 

The correct type for names is string[] | undefined. The undefined type caters to the edge case where the names stream is empty — the promise returned by toPromise then resolves to undefined. There is the additional issue that the mentioned edge case is indistinguishable from that of a non-empty observable that emits one undefined value. This leads to the deprecation of the toPromise method.

Lesh also mentioned that union types returns are better. The following code will have the type result correctly inferred to Observable<string | number> :

const result = of(Math.random()).pipe( concatMap(n => n > 0.5 ? of ('life') : of(42)) );    console.log(result); 

This is of special interest for users of the NgRx Angular state management library who use effects that may return different types of actions. Such users will no longer have to explicitly type the returned entities.

The deprecated toPromise is replaced by two new methods: lastValueFrom and firstValueFrom. Both methods take an observable and return a promise. In case of being passed an empty observable, both methods will throw an EmptyError exception.

RxJS 7 should also support using asynchronous generators in all RxJS methods that accept promises or observables (e.g. concatMap, mergeMap, defer, and more). Asynchronous generators being a standard feature of JavaScript, the support offers new possibilities to use vanilla JavaScript for asynchronous processing (e.g. polling, reading I/O streams chunk by chunk) — or simply reuse existing libraries leveraging asynchronous iteration.

On the other hand, RxJS 7 will not support asynchronous iteration of observables. Instead, developers can use the (rxjs-for-await) library that distinguishes 4 strategies for asynchronously iterating over observables. The 4 strategies result from the existence of a producer (the observable) that is decoupled from the consumer (the iterating loop), possibly creating back-pressure issues.

Observables push values while iterators pull them, and pushing values faster than the iterator pull them forces either to drop values (lossy strategies) or buffer them (lossless strategy). Buffered values can be passed individually (eachValueFrom) or together (bufferedValuesFrom). Lossy strategies involve pulling the most recent value (latestValueFrom) emitted by the observable, or the next one (nextValueFrom). Lesh reminded the audience that the IxJS library is an actively developed counterpart of RxJS dealing with iterables.

Some operators have been renamed (for instance zip is renamed to zipWith). The RxJS team is removing schedulers from several methods (e.g. interval, auditTime) and recommends the new scheduled and observedOn API. A key goal behind the move is to reduce the footprint of the RxJS methods for those users who do not use schedulers.

RxJS is now in Beta 7 and can be installed as follows:

npm install rxjs@next  

The full video of the talk contains many additional technical details and valuable comments. ng-conf is a three-day Angular conference that strives to deliver the highest quality training in the Angular JavaScript framework. ng-conf took place in Salt Lake City in April 2020 and gathered more than 1,500 developers.