"User is Typing" 精益 RXJS 实现
"User is Typing" lean RXJS implementation
我目前正在为多用户聊天室实现“用户正在输入”功能。由于我对 RXJS 的了解有限,我能够生成以下代码片段,它满足“用户正在键入”功能的最低要求:
this.messageForm.message.valueChanges
.pipe(
tap(() => this.convoService.isUserTyping(true)),
debounceTime(500),
map(() => this.convoService.isUserTyping(false))
)
.subscribe();
但是这个实现并不理想,因为它对服务器产生了太多的请求。我的目标是 将请求限制为 2,并使用 RXJS 运算符创建以下行为:
- 仅在第一次按键时发出请求
- 忽略所有后续按键
- 在可能是最后一次按键之后等待 X 时间
- 如果在倒计时结束前引入新按键,则重置倒计时
- 倒计时结束后发出请求
这是一个 side-effect 实现它的免费方法:
const typing$ = this.messageForm.message.valueChanges.pipe(
switchMap(() => concat(
of(true),
of(false).pipe(delay(500)),
)),
distinctUntilChanged(),
)
您可以使用它来执行您的请求。如果 isUserTyping
是 fire-and-forget,你可以做
typing$.subscribe(typing => this.convoService.isUserTyping(typing));
如果它是一个异步请求(并返回一个可观察的),我宁愿这样做:
typing$.pipe(
concatMap(typing => this.convoService.isUserTyping(typing))
).subscribe();
这样可以确保按顺序执行所有请求,避免 out-of-order high-latency 情况下的问题¹。
¹ 如果延迟是一个实际问题,这将需要使用缓冲进行更多工作,以避免对请求施加过多的背压,但这无论如何都超出了这个问题的范围。
我目前正在为多用户聊天室实现“用户正在输入”功能。由于我对 RXJS 的了解有限,我能够生成以下代码片段,它满足“用户正在键入”功能的最低要求:
this.messageForm.message.valueChanges
.pipe(
tap(() => this.convoService.isUserTyping(true)),
debounceTime(500),
map(() => this.convoService.isUserTyping(false))
)
.subscribe();
但是这个实现并不理想,因为它对服务器产生了太多的请求。我的目标是 将请求限制为 2,并使用 RXJS 运算符创建以下行为:
- 仅在第一次按键时发出请求
- 忽略所有后续按键
- 在可能是最后一次按键之后等待 X 时间
- 如果在倒计时结束前引入新按键,则重置倒计时
- 倒计时结束后发出请求
这是一个 side-effect 实现它的免费方法:
const typing$ = this.messageForm.message.valueChanges.pipe(
switchMap(() => concat(
of(true),
of(false).pipe(delay(500)),
)),
distinctUntilChanged(),
)
您可以使用它来执行您的请求。如果 isUserTyping
是 fire-and-forget,你可以做
typing$.subscribe(typing => this.convoService.isUserTyping(typing));
如果它是一个异步请求(并返回一个可观察的),我宁愿这样做:
typing$.pipe(
concatMap(typing => this.convoService.isUserTyping(typing))
).subscribe();
这样可以确保按顺序执行所有请求,避免 out-of-order high-latency 情况下的问题¹。
¹ 如果延迟是一个实际问题,这将需要使用缓冲进行更多工作,以避免对请求施加过多的背压,但这无论如何都超出了这个问题的范围。