Lettable Operator is a new feature introduced in RxJS 5.5, which was released beta-7 last week. With this feature, flows and operators in RxJS can be combined in a more FP style.

The problem lettable Operator is trying to solve

In previous versions of RxJS 5, operators were combined by dot chaining. In cases where bundle size is considered, the RxJS operators are usually defined as

  • import "rxjs/add/operator/SOME_OPERATOR" (instace operator)
  • import "rxjs/add/observable/SOME_OPERATOR" (static operator)

Is added to the application. In this way, you avoid packaging the entire RxJS.

The introduction of this RXJS/Add style is equivalent to dynamically adding operators to Observables and Observables. Prototype outside of the RXJS library. This makes it almost impossible for RxJS to benefit from WebPack 2 or rollup tree-shaking.

Additionally, TypeScript, Flow, or various Linters will not report errors if the imported operators are not used. Considering the wide variety of operators in RxJS, there are a lot of cases where operators are constantly changed during the encoding process, and sometimes operators are forgotten to be deleted, resulting in an increase in bundle size.

How to use lettable Operator

Lettable Operator is a slang name in the RxJS community and there is an issue in the RxJS community about changing the name to a more beginner friendly one.

Lettable operator need to cooperate to observables. Prototype. Pipe used together, use below to see a lettable operator example:

import { range } from 'rxjs/observable/range';
import { map, filter, scan } from 'rxjs/operators';

const source$ = range(0.10);

source$.pipe(
  filter(x= > x % 2= = =0),
  map(x= > x + x),
  scan((acc, x) = > acc + x, 0)
)
.subscribe(x= > console.log(x))Copy the code

In contrast, the dot chaining style is written as follows:

import { Observable } from "rxjs/Observable";
import "rxjs/add/observable/range";
import "rxjs/add/operator/map";
import "rxjs/add/operator/filter";
import "rxjs/add/operator/scan";

const source$ = Observable.range(0.10);

source$
  .filter(x= > x % 2= = =0)
  .map(x= > x + x),
  .scan((acc, x) = > acc + x, 0)
  .subscribe(x= > console.log(x));Copy the code

Pipelines made of lettable Operators are much closer to the popular FP style than dot chaining. More importantly, this approach is much more convenient than the RXJS /add/* style of dot chaining when introducing operators.

Therefore, there are related issues discussing whether to release the RXJS/Add /* style introduction in 6.0 to another NPM package.

Principles of lettable Operator

Observables. Prototype. Pipe code is as follows:

import { pipeFromArray } from './util/pipe';

class Observable<T> implementsSubscribable<T> { pipe<R>(... operations: OperatorFunction<T, R>[]): Observable<R> {if (operations.length === 0) {
      return this as any;
    }

    return pipeFromArray(operations)(this); }}Copy the code

Here we call the function returned by pipeFromArray’s higher-order function in./util/pipe:

export function pipeFromArray<T.R> (fns: Array<UnaryFunction<T, R>>) :UnaryFunction<T.R> {
  if(! fns) {return noop as UnaryFunction<any.any>;
  }

  if (fns.length === 1) {
    return fns[0];
  }

  return function piped(input: T) :R {
    return fns.reduce((prev: any, fn: UnaryFunction<T, R>) = > fn(prev), input);
  };
}Copy the code

In this process, Piped gets this of Observable and uses it as the initial value in reduce process.

At the end of the Reduce method, you have the desired Observable.

Reference

  • Lettable operator document
  • WIP: Adding lettable operators – ReactiveX/rxjs