Document generateKeyed$ more thoroughly

This commit is contained in:
Robin
2025-10-21 00:27:18 -04:00
parent 27f24ca565
commit 1b3a56427f
2 changed files with 17 additions and 0 deletions

View File

@@ -762,6 +762,8 @@ export class CallViewModel {
MediaItem, MediaItem,
MediaItem[] MediaItem[]
>( >(
// Generate a collection of MediaItems from the list of expected (whether
// present or missing) LiveKit participants.
combineLatest([this.participantsByRoom$, duplicateTiles.value$]), combineLatest([this.participantsByRoom$, duplicateTiles.value$]),
([participantsByRoom, duplicateTiles], createOrGet) => { ([participantsByRoom, duplicateTiles], createOrGet) => {
const items: MediaItem[] = []; const items: MediaItem[] = [];

View File

@@ -125,6 +125,14 @@ export function pauseWhen<T>(pause$: Behavior<boolean>) {
* automatically created when their key is requested for the first time, reused * automatically created when their key is requested for the first time, reused
* when the same key is requested at a later time, and destroyed (have their * when the same key is requested at a later time, and destroyed (have their
* scope ended) when the key is no longer requested. * scope ended) when the key is no longer requested.
*
* @param input$ The input value to be mapped.
* @param project A function mapping input values to output values. This
* function receives an additional callback `createOrGet` which can be used
* within the function body to request that an item be generated for a certain
* key. The caller provides a factory which will be used to create the item if
* it is being requested for the first time. Otherwise, the item previously
* existing under that key will be returned.
*/ */
export function generateKeyed$<In, Item, Out>( export function generateKeyed$<In, Item, Out>(
input$: Observable<In>, input$: Observable<In>,
@@ -137,6 +145,7 @@ export function generateKeyed$<In, Item, Out>(
) => Out, ) => Out,
): Observable<Out> { ): Observable<Out> {
return input$.pipe( return input$.pipe(
// Keep track of the existing items over time, so we can reuse them
scan< scan<
In, In,
{ {
@@ -150,22 +159,28 @@ export function generateKeyed$<In, Item, Out>(
string, string,
{ item: Item; scope: ObservableScope } { item: Item; scope: ObservableScope }
>(); >();
const output = project(data, (key, factory) => { const output = project(data, (key, factory) => {
let item = state.items.get(key); let item = state.items.get(key);
if (item === undefined) { if (item === undefined) {
// First time requesting the key; create the item
const scope = new ObservableScope(); const scope = new ObservableScope();
item = { item: factory(scope), scope }; item = { item: factory(scope), scope };
} }
nextItems.set(key, item); nextItems.set(key, item);
return item.item; return item.item;
}); });
// Destroy all items that are no longer being requested
for (const [key, { scope }] of state.items) for (const [key, { scope }] of state.items)
if (!nextItems.has(key)) scope.end(); if (!nextItems.has(key)) scope.end();
return { items: nextItems, output }; return { items: nextItems, output };
}, },
{ items: new Map() }, { items: new Map() },
), ),
finalizeValue((state) => { finalizeValue((state) => {
// Destroy all remaining items when no longer subscribed
for (const { scope } of state.items.values()) scope.end(); for (const { scope } of state.items.values()) scope.end();
}), }),
map(({ output }) => output), map(({ output }) => output),