-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds explaination of flatMap
semantics
#86
Changes from 3 commits
b993bb5
a7191c1
3fa9c0d
bb15499
521407b
ec753d9
c7f3867
114ebd5
31e791a
00e07ff
b1f3b1f
1f7146e
f29432d
63102e4
3fab159
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -507,6 +507,10 @@ We propose the following operators in addition to the `Observable` interface: | |
- `finally()` | ||
- Like `Promise.finally()`, it takes a callback which gets fired after the | ||
observable completes in any way (`complete()`/`error()`) | ||
- `flatMap()` | ||
|
||
- Similar to `Iterator.prototype.flatMap`, however, because the types are different, | ||
there are some semantics to note. | ||
|
||
Versions of the above are often present in userland implementations of | ||
observables as they are useful for observable-specific reasons, but in addition | ||
|
@@ -554,6 +558,55 @@ Promises whose scheduling differs from that of Observables, which sometimes | |
means event handlers that call `e.preventDefault()` will run too late. See the | ||
[Concerns](#concerns) section which goes into more detail. | ||
|
||
### flatMap semantics | ||
|
||
`flatMap` generally behaves like `Iterator.prototype.flatMap`, however, since it's push-based, | ||
there can be a temporal element. Given that, it behaves much like RxJS's `concatMap`, which is | ||
one of the most useful operators from the library. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think we can remove this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ping |
||
|
||
At a high-level, it subscribes to the source, and then maps to, and emits values from "inner | ||
observables", one at a time, ensuring they're subscribed to in sequence. | ||
|
||
Given the following example: | ||
|
||
```ts | ||
const result = source.flatMap((value) => getNextInnerObservable(value)); | ||
``` | ||
|
||
- When you subscribe to `result`, it subscribes to `source` immediately. | ||
- Let there be a `queue` of values that is empty. | ||
- Let there be an `innerSignal` that is either `undefined` or an `AbortSignal` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which is it? Does this mean to represent the signal that's passed into the subscription of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's correct. I'll add something. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, I do explain that below: |
||
- Let there be an `isSourceComplete` that is `false`. | ||
benlesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- When the `source` emits a value: | ||
- If `innerSignal` is `undefined` | ||
- Call the mapping function with the the value. | ||
benlesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Then pass the return value of the mapping function to `Observable.from()` to convert it to | ||
"inner observable" if it's not already. | ||
- Then create an `AbortSignal` that follows the subscriber's and set `innerSignal`. | ||
benlesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- pass the `innerSignal` to the subscribe for the inner observable. | ||
benlesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Forward all values emitted by the inner observable to the `result` observer. | ||
- If the inner observable completes | ||
- If there are values in the `queue` | ||
- take the first one from the `queue` and return the the mapping step. | ||
benlesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- If the `queue` is empty | ||
- If `isSourceComplete` is `true` | ||
- Complete `result`. | ||
- If `isSourceComplete` is `false` | ||
- Wait | ||
- If the inner observable errors | ||
- Forward the error to `result`. | ||
- If `innerSignal` is `AbortSignal` | ||
benlesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Add the value to the `queue` and wait. | ||
- If the `source` completes: | ||
- If `innerSignal` is `undefined` | ||
- Complete `result`. | ||
- If `innerSignal` is `AbortSignal` | ||
- set `isSourceComplete` to `true`. | ||
benlesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- If the `source` errors: | ||
- Forward the error to `result`. | ||
- If the user aborts the signal passed to the subscription of `result` | ||
- Abort any `innerSignal` that exists, and terminate subscription. | ||
|
||
## Background & landscape | ||
|
||
To illustrate how Observables fit into the current landscape of other reactive | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should appear both in this "exceptional" list, and in the list below about iterator helpers. Seems like it should just exist in the list of iterator helpers, with a note that the semantics are a little different (as you provided below).