admin管理员组

文章数量:1290951

I know a little bit of BaconJS, but now I'm trying to learn RxJS by creating a "User is typing..." indicator. It's pretty simple, it can be explained in two simple rules:

  1. When the user is typing, the indicator should be immediately visible.
  2. When the user stops typing, the indicator should still be visible until 1 second after the user's last typing action.

I'm not sure if this is correct, but I have so far created two streams:

  1. One heartbeat stream that emits a 0 every second.
  2. One stream to capture the user typing events and emit a 1 for every event.

Then I merge them together, and simply tap into the result. If it's a 1, then I show the indicator. If it's a 0, then I hide the indicator.

This is what that looks like:

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);

Here is a link to the JSBin:

,console,output

There are several problems and questions I have with this implementation:

  1. Sometimes when the user is typing, a 0 sneaks through, so the indicator flashes away for a split second before ing back on the next user keystroke.
  2. It's not guaranteed that the indicator will disappear 1 second after the user stops typing. It's only guaranteed that the indicator will disappear within 1 second (which is kind of the opposite of what we want).
  3. Is using a heartbeat stream the correct RxJS way to do this? I have a feeling it might not be.

I have a feeling that I am pletely off-base with my implementation, I appreciate any help that you may be able to provide. Thanks.

I know a little bit of BaconJS, but now I'm trying to learn RxJS by creating a "User is typing..." indicator. It's pretty simple, it can be explained in two simple rules:

  1. When the user is typing, the indicator should be immediately visible.
  2. When the user stops typing, the indicator should still be visible until 1 second after the user's last typing action.

I'm not sure if this is correct, but I have so far created two streams:

  1. One heartbeat stream that emits a 0 every second.
  2. One stream to capture the user typing events and emit a 1 for every event.

Then I merge them together, and simply tap into the result. If it's a 1, then I show the indicator. If it's a 0, then I hide the indicator.

This is what that looks like:

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);

Here is a link to the JSBin:

http://jsbin./vekixuv/edit?js,console,output

There are several problems and questions I have with this implementation:

  1. Sometimes when the user is typing, a 0 sneaks through, so the indicator flashes away for a split second before ing back on the next user keystroke.
  2. It's not guaranteed that the indicator will disappear 1 second after the user stops typing. It's only guaranteed that the indicator will disappear within 1 second (which is kind of the opposite of what we want).
  3. Is using a heartbeat stream the correct RxJS way to do this? I have a feeling it might not be.

I have a feeling that I am pletely off-base with my implementation, I appreciate any help that you may be able to provide. Thanks.

Share Improve this question edited Jan 7, 2017 at 12:00 martin 97k26 gold badges203 silver badges235 bronze badges asked Jan 7, 2017 at 11:25 adrianmcliadrianmcli 1,9963 gold badges23 silver badges49 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 10

You don't even need to use two Observables and use just one with debounceTime(). All the logic you tried to make is already present in 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());

See live demo: http://jsbin./cixipa/6/edit?js,console,output

You don't need a heartbeat for this, just emit change-events whenever something 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);

See live here.

The switchMap, will discard any previouse 1s-timer whenever a new typing-event is emitted.

本文标签: javascriptHow to use RxJS to display a quotuser is typingquot indicatorStack Overflow