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

[Idea] Make it possible for BehaviorSubject to emit an initial "summary" value to late subscribers #7297

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

vkryachko
Copy link

Description:

Note: this PR is intended to open a discussion on whether this change is considered broadly useful

BehaviorSubject currently allows emitting the initial or latest value when it's subscribed to. However there is a use case that it non-trivial to model with it.

Imagine a BehaviorSubject is used to stream log events and consumers can subscribe and render them. However the logs subscribers will receive depends on when they subscribe, late subscribers won't see log events that happened before they subscribed.

This change proposes to make it possible for late subscribers to receive a "summary" value upon initial subscription, e.g.

interface LogEvent {
  readonly log: string;
}

const events = new BehaviorSubject<LogEvent>(
    {log: "start"},
    (prev, next) => {log: `${prev.log}\n${next.log}`.slice(-2000)});

With this code, late subscribers will receive up to 2000 characters of previously emitted logs and then keep receiving new log lines as long as they are subscribed.
While this example it contrived, the proposed change is general enough to allow for more interesting folds to generate a meaningful "summary" value.

Thoughts?

BREAKING CHANGE: NA

@voliva
Copy link
Contributor

voliva commented Jun 29, 2023

If you don't need to "summarise" and you only need to keep the last 2000 logs, you can just use new ReplaySubject(2000) instead of new BehaviourSubject(). The consumer then can take those 2000 logs when it subscribes and change them / summarise them as they need.

But if for whatever reason you want to pre-summarise it and store that as a separate value, then I think you can just break it in a separate observable:

const events = new Subject<LogEvent>(); // BehaviourSubject not needed

const eventSummary = connectable(events.pipe(
  scan((prev, next) => ({log: `${prev.log}\n${next.log}`.slice(-2000)}), {log: "start"}),
), {
  connector: () => new ReplaySubject(1)
});
eventSummary.connect()

In a way, if I subscribe to events I expect not to receive the last log event, that's why I think Subject is usually more suitable.
And if I need the summary I can subscribe to eventSummary, or even combine them both so I can receive the summary followed by the new ones.

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