如何使用 RxJS 显示 "user is typing" 指标?
How to use RxJS to display a "user is typing" indicator?
我对 BaconJS 了解一点,但现在我正在尝试通过创建一个 "User is typing..." 指标来学习 RxJS。这很简单,可以用两个简单的规则来解释:
- 当用户输入时,指示符应该立即可见。
- 当用户停止输入时,该指示器应在用户最后一次输入操作 1 秒后仍然可见。
我不确定这是否正确,但到目前为止我已经创建了两个流:
- 每秒发出
0
一个心跳流。
- 一个流来捕获用户键入事件并为每个事件发出
1
。
然后我将它们合并在一起,然后简单地利用结果。如果它是 1
,那么我会显示指标。如果它是 0
,那么我会隐藏指示器。
这就是它的样子:
const showTyping = () =>
$('.typing').text('User is typing...');
const showIdle = () =>
$('.typing').text('');
// 1 second heartbeats are mapped to 0
const heartbeat$ = Rx.Observable
.interval(1000)
.mapTo(0);
// user typing events are mapped to 1
const input$ = Rx.Observable
.fromEvent($('#input'), 'input')
.mapTo(1);
// we merge the streams together
const state$ = heartbeat$
.merge(input$)
.do(val => val === 0 ? showIdle() : showTyping())
.subscribe(console.log);
这是 JSBin 的 link:
http://jsbin.com/vekixuv/edit?js,console,output
我对这个实现有几个问题和疑问:
- 有时,当用户输入时,
0
会偷偷溜过,因此指示灯会闪烁一瞬间,然后在下一次用户击键时返回。
- 不能保证指示器会在用户停止输入后 1 秒消失。只保证指示器会在 1 秒内消失(这与我们想要的有点相反)。
- 使用心跳流是正确的 RxJS 方法吗?我感觉可能不是。
我觉得我的实现完全偏离了基础,非常感谢您提供的任何帮助。谢谢。
你不需要心跳,只要有事情发生就发出变化事件happens/changes:
const showTyping = () =>
$('.typing').text('User is typing...');
const showIdle = () =>
$('.typing').text('');
// user typing events
const input$ = Rx.Observable
.fromEvent($('#input'), 'input');
// user stopped typing
const stoppedTypingAfter1s$ = input$
.switchMapTo(Rx.Observable.timer(1000));
// we merge the streams together
const state$ = Rx.Observable.merge(
input$.mapTo(1),
stoppedTypingAfter1s$.mapTo(0)
)
.startWith(0)
.do(val => val === 0 ? showIdle() : showTyping())
.subscribe(console.log);
看直播here。
switchMap
将在发出新的输入事件时丢弃任何先前的 1s 计时器。
您甚至不需要使用两个 Observable,只需使用一个 debounceTime()
。您尝试创建的所有逻辑都已存在于 debounceTime()
operator:
中
const showTyping = () =>
$('.typing').text('User is typing...');
const showIdle = () =>
$('.typing').text('');
const input$ = Rx.Observable
.fromEvent($('#input'), 'input')
.do(() => showTyping())
.debounceTime(1000)
.subscribe(() => showIdle());
我对 BaconJS 了解一点,但现在我正在尝试通过创建一个 "User is typing..." 指标来学习 RxJS。这很简单,可以用两个简单的规则来解释:
- 当用户输入时,指示符应该立即可见。
- 当用户停止输入时,该指示器应在用户最后一次输入操作 1 秒后仍然可见。
我不确定这是否正确,但到目前为止我已经创建了两个流:
- 每秒发出
0
一个心跳流。 - 一个流来捕获用户键入事件并为每个事件发出
1
。
然后我将它们合并在一起,然后简单地利用结果。如果它是 1
,那么我会显示指标。如果它是 0
,那么我会隐藏指示器。
这就是它的样子:
const showTyping = () =>
$('.typing').text('User is typing...');
const showIdle = () =>
$('.typing').text('');
// 1 second heartbeats are mapped to 0
const heartbeat$ = Rx.Observable
.interval(1000)
.mapTo(0);
// user typing events are mapped to 1
const input$ = Rx.Observable
.fromEvent($('#input'), 'input')
.mapTo(1);
// we merge the streams together
const state$ = heartbeat$
.merge(input$)
.do(val => val === 0 ? showIdle() : showTyping())
.subscribe(console.log);
这是 JSBin 的 link:
http://jsbin.com/vekixuv/edit?js,console,output
我对这个实现有几个问题和疑问:
- 有时,当用户输入时,
0
会偷偷溜过,因此指示灯会闪烁一瞬间,然后在下一次用户击键时返回。 - 不能保证指示器会在用户停止输入后 1 秒消失。只保证指示器会在 1 秒内消失(这与我们想要的有点相反)。
- 使用心跳流是正确的 RxJS 方法吗?我感觉可能不是。
我觉得我的实现完全偏离了基础,非常感谢您提供的任何帮助。谢谢。
你不需要心跳,只要有事情发生就发出变化事件happens/changes:
const showTyping = () =>
$('.typing').text('User is typing...');
const showIdle = () =>
$('.typing').text('');
// user typing events
const input$ = Rx.Observable
.fromEvent($('#input'), 'input');
// user stopped typing
const stoppedTypingAfter1s$ = input$
.switchMapTo(Rx.Observable.timer(1000));
// we merge the streams together
const state$ = Rx.Observable.merge(
input$.mapTo(1),
stoppedTypingAfter1s$.mapTo(0)
)
.startWith(0)
.do(val => val === 0 ? showIdle() : showTyping())
.subscribe(console.log);
看直播here。
switchMap
将在发出新的输入事件时丢弃任何先前的 1s 计时器。
您甚至不需要使用两个 Observable,只需使用一个 debounceTime()
。您尝试创建的所有逻辑都已存在于 debounceTime()
operator:
const showTyping = () =>
$('.typing').text('User is typing...');
const showIdle = () =>
$('.typing').text('');
const input$ = Rx.Observable
.fromEvent($('#input'), 'input')
.do(() => showTyping())
.debounceTime(1000)
.subscribe(() => showIdle());