Projects each element of an observable sequence to an observable sequence and merges the resulting observable sequences or Promises or array/iterable into one observable sequence.
Returns an observable sequence which results from the comonadic bind operation.
Rx.observable.prototype.flatMap
Rx.observable.prototype.scan
The Reactive Extensions for JavaScript (RxJS) is
a set of libraries to compose asynchronous and event-based programs using observable collections and Array#extras style composition in JavaScript
FRP deals with values that change continuously over time while ReactiveX deals with discrete values that are emitted over time.
reactive programming is a programming paradigm oriented around data flows and the propagation of change
[clickEvent, clickEvent, clickEvent]
[clickEvent, clickEvent, clickEvent] .map(e => e.screenX) .forEach(x => console.log(x));
Due to lack of generators, continuation-style passing in JavaScript can be tricky, and error handling is a mess.
How to ensure that events arrive in order?
There're not many libraries (except perhaps BlueBird) that provide async-capable APIs with functional helpers similar to LoDash / Underscore / Ramda.
Consider an aborted XMLHTTPRequest. Promise-based AJAX implementations are unable to handle abort by design.
By the time you have a promise, it's already on its way to being resolved or rejected. There is no declarative way to describe an async operation.
DOM events, WebSocket, server-sent events, and app life cycle events produce multiple values over time making it Promises a dubious fit.
The Observable object represents a push based collection.
Operators are chainable methods that create and operate on Observables.
A Subject is a sort of bridge that acts both as an observer and as an Observable.
A scheduler controls when a subscription starts and when notifications are published.
Observer
Pattern
Iterator
Pattern
Observable
sequence
const source = Rx.Observable.create(observer => {
// push some value to the observer:
observer.onNext(42);
observer.onNext(43);
// inform observer that there will be no more events:
observer.onCompleted();
// provide a dispose function:
return () => console.log('disposed');
});
const subscription = source.subscribe(
value => console.log(`Got a value ${value}`),
error => console.error(`Found an error ${error}`),
() => console.log('Completed')
);
// "Got a value 42"
// "Got a value 43"
// "Completed"
subscription.dispose();
// "disposed"
const source = Rx.Observable.just(42);
const subscription = source.subscribe(
value => console.log(value),
error => console.error(error),
() => console.log('completed')
);
// 42
// "completed"
const source = Rx.Observable.range(0, 3);
const subscription = source.subscribe(
value => console.log(value),
error => console.error(error),
() => console.log('completed')
);
// 0
// 1
// 2
// "completed"
function promiseFactory() {
return Promise.resolve(42);
}
const source = Rx.Observable.fromPromise(promiseFactory());
const subscription = source.subscribe(
value => console.log(value),
error => console.error(error),
() => console.log('completed')
);
// 42
// "completed"
const source = Rx.Observable.fromEvent(input, 'keyup');
const subscription = source.subscribe(
value => console.log(value)
);
// [KeyboardEvent]
// [KeyboardEvent]
// ...
const bestPlaceToWork = Rx.Observable.fromEvent(input, 'keyup')
.pluck('target', 'value')
.do(value => console.log(`Value is ${value}`))
.filter(value => value === 'SFEIR')
.map(company => `Best place to work is ${company}`)
.take(1);
const subscription = bestPlaceToWork.subscribe(
value => console.log(value),
error => console.error(error),
() => console.log('completed')
);
// "Value is S"
// "Value is SF"
// "Value is SFE"
// "Value is SFEI"
// "Value is SFEIR"
// "Best place to work is SFEIR"
// "completed"
[1, 2, 3]
.filter(x => x < 2)
.map(x => x * 2);
Rx.Observable.from([1, 2, 3])
.filter(x => x < 2)
.map(x => x * 2);
Array#extras
RxJS operators
imperative style
everything is executed at once; needs to be wrapped in a function to be reusable
declarative style
nothing is executed until subscription;
reusable as is
performance issue
intermediate arrays have been created while calling operators
stream-like behavior
RxJS passes values through operators in the same way a stream passes data through pipes, without creating intermediate arrays