perf(client): share replay of computed observables #1095
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Overview
Adds
shareReplay
to computed observables which when previously subscribed to by multiple components would be evaluated separately, i.e., each source data emission would evaluate defined pipeline for each subscription individually."Futureproofs"
RxUtils.getCurrentValue
method through usage ofcombineLatest
function which will always take the last emitted value even from "pure" observables unliketake
operator which "resolves" with first emitted value.Fixes
noop
sorting (\w) test where "sort" mutates source data - when we move to TS5.2 we should replace that withArray.toSorted
.Implementation notes
I mentioned using
share
operator which usesrefCount
andSubject
under the hood meaning that if amount of subscriptions on such observable reaches 0 (refCount === 0) - it resets theSubject
and re-evaluates the pipeline and assignes new value on next subscription. Using it in our SDK proved to be difficult and was behaving unexpectedly (broke tests and certain observables would return "undefined" instead of initial values) though on paper it makes perfect sense. I opted to useshareReplay
which by default (with only buffer size as argument) works like aReplaySubject
but continues running defined pipeline (never unsubscribes from the source observable) even after therefCount
reached zero. With the overloaded variantshareReplay({ bufferSize: 1, refCount: true })
it behaves just as expected and does not break our SDK - meaning the values (pipelines) are being computed only once per multiple subscriptions and only if it has at least one subscription.Sources:
share
andshareReplay
operators - though I found a discrepancy in the post - they mention that theshareReplay
withrefCount
does not re-evaluate source observable but through my testing I found that to be false (yet it does something differently under the hood)shareReplay
operatorshare
operator