angular - "Användaren skriver" lätt RXJS-implementation


Jag arbetar för närvarande med att implementera en "Användaren skriver"-funktion för ett chattrum med flera användare. Med min begränsade kunskap om RXJS lyckades jag ta fram följande kodsnutt som uppfyller minimikraven för "Användaren skriver"-funktionen:

   this.messageForm.message.valueChanges
      .pipe(
        tap(() => this.convoService.isUserTyping(true)),
        debounceTime(500),
        map(() => this.convoService.isUserTyping(false))
      )
      .subscribe();

Denna implementation är dock inte ideal eftersom den genererar för många förfrågningar till servern. Mitt mål är att begränsa förfrågningarna till 2, och genom att använda RXJS-operatörer skapa följande beteenden:

  1. Skicka endast en förfrågan vid första knapptryckningen
  2. Ignorera alla efterföljande knapptryckningar
  3. Vänta en X mängd tid efter vad som kan vara den sista tangenttryckningen
  4. Återställ nedräkningen om en ny tangenttryckning sker innan nedräkningen går ut
  5. Skicka en förfrågan när nedräkningen har löpt ut

Svar #1

Här är ett sätt att uppnå det utan bieffekter:

const typing$ = this.messageForm.message.valueChanges.pipe(
  switchMap(() => concat(
    of(true),
    of(false).pipe(delay(500)),
  )),
  distinctUntilChanged(),
)

Du kan använda det för att utföra dina förfrågningar. Om isUserTyping är en fire-and-forget, kan du bara göra

typing$.subscribe(typing => this.convoService.isUserTyping(typing));

Om det är en asynkron förfrågan (och returnerar ett observerbart) skulle jag helst gå med detta:

typing$.pipe(
  concatMap(typing => this.convoService.isUserTyping(typing))
).subscribe();

På så sätt säkerställer du att alla förfrågningar utförs i ordningsföljd, vilket undviker problem med fel ordning i situationer med hög latens¹.


¹ Om latens verkligen var ett problem skulle detta kräva ännu mer arbete med buffring för att istället undvika att trycka tillbaka förfrågningarna för mycket, men detta är i alla fall utanför omfattningen för denna fråga.