Vyhledávání na webu

javascript - RxJS zpoždění (Debounce) s prioritou


Mám problém vymyslet tento proud.

Co hledám, je něco jako debounceTime, ale s prioritou.

Takže pokud mám události ve tvaru { type: 'a', priority: 2 }. Tyto události je potřeba spouštět s debounce několika sekund, ale místo toho, aby byla vyvolána poslední událost, je vyvolána událost s nejvyšší prioritou.

input stream:
------(a|1)--(b|3)---(c|2)-----------------------(a|1)-----------------


output stream:
-----------------------------------(b|3)---------------------(a|1)-----

Zkoušel jsem se podívat na jiné operátory jako window a filtrovat výsledky pro poslední událost, ale není to ideální, protože window pracuje na pevně stanoveném rytmu, zatímco já chci, aby časovač začal při první události, stejně jako debouncing.

Odpověď č. 1

Musíte uložit a aktualizovat položku s nejvyšší prioritou a mapovat na tuto hodnotu highest, kterou pak předáte do debounceTime.

let highest = null;
source$.pipe(
  map(v => highest = highest && highest.priority > v.priority ? highest : v),
  debounceTime(2000),
  tap(() => highest = null)
);

Můžete si vytvořit vlastní operátor, který to dělá, s pomocí defer. defer zajišťuje, že každý odběratel dostane svou vlastní proměnnou highest, protože každý odběratel získá vlastní nový Observable vytvořený voláním dané tovární funkce.

function debounceTimeHighest<T>(dueTime: number, getHighest: (curr: T, high: T) => T): MonoTypeOperatorFunction<T> {
  return (source: Observable<T>) => defer(() => {
    let highest: T = null;
    return source.pipe(
      map(item => highest = highest ? getHighest(item, highest) : item),
      debounceTime(dueTime),
      tap(() => highest = null)
    );
  });
}

// Usage
source$.pipe(
  debounceTimeHighest(2000, (v1, v2) => v1.priority >= v2.priority ? v1 : v2)
)

Výše uvedený kód je v Typescriptu. Pokud chcete čistý Javascript, jednoduše odstraňte všechny typy.

https://stackblitz.com/edit/rxjs-hitqxk

Odpověď č. 2

Nabídnu následující řešení, založené na použití scan k nabídnutí dosud nejvyšší přiřazené prioritní emise k posouzení debounceTime(). Všimněte si, že scan musí po každém úspěšném debounce znovu zvážit nová data, takže používám operátor window() k rozdělení emisí, přičemž nové okno observable začíná po každé emisi debounceTime().

Tady je CodeSandbox

A zde je nějaký zjednodušený kód z CodeSandbox ukazující důležité části:

const resetScan$ = new Subject();

source$.pipe(
  window(resetScan$),
  mergeMap(win$ => win$.pipe(
    scan((acc, cur) => acc.priority >= cur.priority ? acc : cur )
  )),
  debounceTime(debounceDelay),
  tap(() => resetScan$.next())
);