Building observables:
-
Primitives (a.k.a. Kinds of things):
- Observable:
- A (subscription) function that takes in an observer, sets up some connections to a data source, and returns a function that can be called to unsubscribe.
- The actual implementation of Observable is not the
subscribe
function, but has thesubscribe
function as a method. It's kind of like how you can make something that represents a function and then say, "But to call it, you need to call its.run
method." - The actual implementation returns a
Subscription
object, not anunsubscribe
function.
- The actual implementation of Observable is not the
- Can have a cleanup function internally.
- Should be called upon unsubscription (cancelling the Observable).
- Should be called upon
error
orcomplete
from the data source. next
should not be called after it.- Is the cleanup function?
- A (subscription) function that takes in an observer, sets up some connections to a data source, and returns a function that can be called to unsubscribe.
- Observer: Subscribes to (a single) Observable.
Has one to three of the following methods:
.next(value)
: Send next value from the Observable..error(err)
: Error in the Observable. No more values will be sent..complete()
: Observable finished without error. No more values will be sent.
- Listener: == Observer
- Operator: Conceptually: When given an Observable and an Observer, creates an Observer/Observable pair such that the new Observer subscribes to the original Observable, and the new Observable is subscribed to the original Observer. Defining the relationship of the pair defines the operator. Actually: An Observable that, when subscribed to by an Observer, starts emitting to the Observer based on when it receives and based on its own internal logic (mapping what it receives to what it sends). - Compare with Function. The Operator maps input stream to output stream, but some inputs might not create output, and some inputs can result in multiple or delayed outputs.
- Observable:
-
Observables can be constructed from:
- function:
new Observable(subscribe)
, wheresubscribe
is a function that is called when this Observable is subscribed to.subscribe
should take in an Observer and return anunsubscribe
callback. - Promise:
Rx.from(myPromise)
. Emits the value from the promise when it resolves, and then completes. - Observable:
Rx.from(myObservable)
. ? Why does this exist? Is it just for convenience of not typechecking? - Array or Iterator:
Rx.from([1,2,3])
. Emits each value from the array, then completes. - Event:
Rx.fromEvent(target, eventName, [options and stuff])
. Turns an event emitter into an Observable that emits events.Rx.fromEventPattern
might exist to customize the eventHandler handling, for custom event systems.
- function:
-
Probably a monad?
-
Comparison with Promise:
- I think Observable is conceptually a generalization of Promise, but isn't practically so: a Promise can't substitute for an Observable (doesn't have the Observable interface), so it's not a subtype of Observable. However, RxJS SEEMS to allow Promises whenever it allows Observables, and you can wrap a Promise in an Observable.
- However, maybe Observable objects are NOT like Promise objects conceptually, either. They might represent a different layer of abstraction, like addition is not a number.
- Promises only emit one value.
- Once they emit the value, asking for the value again will get the same value.
- If two observers subscribe to the same observable, they might not receive the same values.
- Wait, then what DO they get? Does only the first one get the values?
- If two observers subscribe to the same observable, they might not receive the same values.
- I think Observable is conceptually a generalization of Promise, but isn't practically so: a Promise can't substitute for an Observable (doesn't have the Observable interface), so it's not a subtype of Observable. However, RxJS SEEMS to allow Promises whenever it allows Observables, and you can wrap a Promise in an Observable.
== Specific operators ==
- concatMap(fn: x => obs) concats fn(x0), fn(x1), etc. It's like Array#flatMap(fn: x => arr).
- E.g. [1,2], [3,4] => [1,2,3,4], waiting for the 2 before it starts on the 3.
- concatMap listens for observer.complete() to determine when to subscribe to the next stream.
- E.g. [1,2], [3,4] => [1,2,3,4], waiting for the 2 before it starts on the 3.
- mergeMap is similar, except instead of taking all of the first result's items and then the second's, it takes from both streams as the streams emit them.
- E.g. [1,2], [3,4] can result in [3,4,1,2] if the [1,2] come out very slowly.
- concatMap(x => [obs0, obs1]) doesn't concatenate obs0 and obs1. It concatenates [obs0, obs1] with the next [obs0, obs1].
- Say we have concatMap(x => twoValues(x)). If twoValues(0) doesn't ever complete, concatMap will never look at twoValues(1).
== Further reading for Franklin ==
https://blog.angular-university.io/rxjs-higher-order-mapping/ https://redux-observable.js.org/docs/basics/Epics.html https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/map.ts