Skip to content
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

Closed
wants to merge 15 commits into from

Conversation

benlesh
Copy link
Collaborator

@benlesh benlesh commented Nov 21, 2023

Basically this is describing RxJS's concatMap. I tried to add it as detailed as possible because "It works like Iterator.prototype.flatMap is only partially true, since there's the element of asynchrony involved here. If all sources and inner sources are synchronous, though, it is exactly like Iterator.prototype.flatMap.

README.md Outdated
@@ -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()`
Copy link
Collaborator

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).

@benlesh benlesh requested a review from domfarolino November 29, 2023 19:18
README.md Outdated

- 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`
Copy link
Collaborator

Choose a reason for hiding this comment

The 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 result? (Clarifying that might be good)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct. I'll add something.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I do explain that below: Pass the innerSignal to the subscribe for the inner observable.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
benlesh and others added 6 commits December 19, 2023 11:18
Co-authored-by: Dominic Farolino <[email protected]>
Co-authored-by: Dominic Farolino <[email protected]>
Co-authored-by: Dominic Farolino <[email protected]>
Co-authored-by: Dominic Farolino <[email protected]>
Co-authored-by: Dominic Farolino <[email protected]>

`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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which is one of the most useful operators from the library.

I think we can remove this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping


```ts
const result = source.flatMap((value, index) =>
getNextInnerObservable(value, index),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the trailing comma here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably aggressive formatting rules. I'll have a look.

- When you subscribe to `result`, it subscribes to `source` immediately.
- Let there be a `queue` of values that is empty.
- Let there be an integer `current index` that is `0`.
- Let there be an `innerSignal` that is either `undefined` or an `AbortSignal`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initially....? Where does this come from? It comes from the subscribe() method being called on the Observable returned by flatMap(), right? Maybe we should mention that. After reading the rest I'm actually thinking that innerSignal is not the one passed into subscribe. So... I'm not sure :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit of state for the internal algorithm. If innerSignal is undefined, there's no current inner subscription. If innerSignal is an AbortSignal, we have an inner subscription, and we need to wait for it to complete before we start another. So we need to buffer the value.

Basically:

let innerSignal: AbortSignal | undefined;

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
- Take the first one from the `queue` and return to the **"mapping step"**.
- If the `queue` is empty
- If `isSourceComplete` is `true`
- Complete `result`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes you have a period and sometimes you don't. Can you edit this whole algorithm to be consistent one way or another?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I can.
Maybe I can't

- If `isSourceComplete` is `true`
- Complete `result`.
- If `isSourceComplete` is `false`
- Wait
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, what is this supposed to do? Certainly we're not blocking the main thread....

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No... Just "wait for another event"... do nothing, I guess.

benlesh and others added 5 commits February 5, 2024 11:40
Co-authored-by: Dominic Farolino <[email protected]>
Co-authored-by: Dominic Farolino <[email protected]>
Co-authored-by: Dominic Farolino <[email protected]>
@domfarolino
Copy link
Collaborator

A few outstanding comments from a while ago still.. I'll wait for those to get resolved.

@domfarolino
Copy link
Collaborator

Since this operator has already made it into the spec https://wicg.github.io/observable/#dom-observable-flatmap, I think this may not be necessary, and seems to have no activity these days anyways. So I'll close it.

@domfarolino domfarolino closed this Apr 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants