For more tips like this, sign up to the weekly newsletter!

How to detect an idle RxJs observable

In some cases, detecting if an Observable hasn't emitted an element for some time is required. Think, for example, a web session that timeouts after some time and you want to send a keepalive just before it happens. Instead of sending it periodically, by detecting inactivity in the network traffic, you can send it just when it is needed.

Use debounceTime()

The easiest way is to use debounceTime(), which detects idleness after an activity:

obs
  .pipe(rxjs.operators.debounceTime(500))
  .subscribe(() => {
    // handle inactivity
  })

Problem #1: It does not detect timeout when there were no elements at all.

This can be easily remedied with a startWith:

obs
  .pipe(
    rxjs.operators.startWith(undefined),
    rxjs.operators.debounceTime(500)
  )
  .subscribe(() => {
    // handle inactivity
  })

Problem #2: Completing the observable also fires the timeout.

To fix this, use a takeUntil with an observable that emits only a single element on completion, for example, count:

obs
  .pipe(
    rxjs.operators.startWith(undefined),
    rxjs.operators.debounceTime(500),
    rxjs.operators.takeUntil(
      obs.pipe(rxjs.operators.count())
    )
  )
  .subscribe(() => {
    // handle inactivity
  })

Try it
Learn more: