如何使用RxJS Observables制作倒数计时器?

时间:2016-01-21 10:45:40

标签: rxjs observable reactive-programming

我正在努力使用Observables创建一个倒数计时器,http://reactivex.io/documentation/operators/timer.html的示例似乎不起作用。在此特定示例中,与timerInterval相关的错误不是从计时器返回的Observable的函数。

我也一直在尝试其他方法,我提出的最好的方法是:

Observable.interval(1000).take(10).subscribe(x => console.log(x));

这里的问题是它从0到10计数,我想要一个倒数计时器,例如10,9,8 ... 0

我也试过这个,但是对于Observable类型

timer不存在
Observable.range(10, 0).timer(1000).subscribe(x => console.log(x));

同样,它根本不产生任何输出。

Observable.range(10, 0).debounceTime(1000).subscribe(x => console.log(x));
  

澄清我需要帮助ReactiveX的RxJS实现,而不是MircoSoft版本。

7 个答案:

答案 0 :(得分:23)

你走在正确的轨道上 - 你的问题是timer在原型上不存在(从而在Observable.range()上),但是在Observable上(参见RxJS docs)。即jsbin

const start = 10;
Rx.Observable
  .timer(100, 100) // timer(firstValueDelay, intervalBetweenValues)
  .map(i => start - i)
  .take(start + 1)
  .subscribe(i => console.log(i));

// or
Rx.Observable
  .range(0, start + 1)
  .map(i => start - i)
  .subscribe(i => console.log(i));

答案 1 :(得分:1)

使用间隔,允许您指定一秒钟的时间

const time = 5 // 5 seconds
var timer$ = Rx.Observable.interval(1000) // 1000 = 1 second
timer$
  .take(time)
  .map((v)=>(time-1)-v) // to reach zero
  .subscribe((v)=>console.log('Countdown', v))

答案 2 :(得分:0)

我是take...()的爱人,所以我按如下方式使用takeWhile()(RxJS 6.x.x,以ES6方式)

import {timer} from 'rxjs';
import {takeWhile, tap} from 'rxjs/operators';


let counter = 10;
timer(1000, 1000) //Initial delay 1 seconds and interval countdown also 1 second
  .pipe(
    takeWhile( () => counter > 0 ),
    tap(() => counter--)
  )
  .subscribe( () => {
    console.log(counter);
  } );

答案 3 :(得分:0)

如果您不想在开始时间依赖变量,请使用<div class="Container" [id]="id"> <img *ngFor="let item of data" [src]="item.url" (click) ="text=item.text"> </div> <!--here show the variable "text"--> <div class="text">{{text}}</div> timerscantakeWhile中的第三个参数是起始数字

scan

Check it out on Stackblitz

答案 4 :(得分:0)

我的带有显示时间的倒计时功能:

import { Observable, timer, of, interval } from "rxjs";
import { map, takeWhile, take } from "rxjs/operators";

function countdown(minutes: number, delay: number = 0) {
   return new Observable<{ display: string; minutes: number; seconds: number }>(
      subscriber => {
        timer(delay, 1000)
          .pipe(take(minutes * 60))
          .pipe(map(v => minutes * 60 - 1 - v))
          .pipe(takeWhile(x => x >= 0))
          .subscribe(countdown => { // countdown => seconds
            const minutes = Math.floor(countdown / 60);
            const seconds = countdown - minutes * 60;

            subscriber.next({
              display: `${("0" + minutes.toString()).slice(-2)}:${("0" + seconds.toString()).slice(-2)}`,
              minutes,
              seconds
            });

            if (seconds <= 0 && minutes <= 0) {
              subscriber.complete();
            }
       });
   });
}

countdown(2).subscribe(next => {
  document.body.innerHTML = `<pre><code>${JSON.stringify(next, null, 4)}</code></pre>`;
});

输出即:

{
   "display": "01:56",
   "minutes": 1,
   "seconds": 56
}

答案 5 :(得分:0)

这个例子对我有用:)

顺便说一句,使用 takeWhile(val => val >= 0) 而不是 take(someNumber) 可能有意义,但它会检查 -1 然后才完成...... 1 秒太晚了。

下面的示例将发出 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0。从 10 开始到 0 立即结束似乎微不足道,但对我来说却相当棘手。

>
const counter$ = interval(1000); // rxjs creation operator - will fire every second
const numberOfSeconds = 10;
counter$.pipe(
    scan((accumulator, _current) =>  accumulator - 1, numberOfSeconds + 1),
    take(numberOfSeconds + 1),

    // optional
    finalize(() => console.log(
      'something to do, if you want to, when 0 is emitted and the observable completes'
    ))
)

这将做同样的事情:


counter$.pipe(
    scan((accumulator, current) => accumulator - 1, numberOfSeconds),
    startWith(numberOfSeconds), // scan will not run the first time!
    take(numberOfSeconds + 1),

    // optional
    finalize(() => console.log(
      'something to do, if you want to, when 0 is emitted and the observable completes'
    ))
  )

当然,您可以进行很多更改。例如,您可以在 mapTo(-1) 之前scan,然后写入 accumulator + currentcurrent 将为 -1 .

答案 6 :(得分:0)

我还需要一个倒数的间隔,所以我尝试了这个解决方案:

// * startPoint => Value of timer continuing to go down
countDown(startPoint: number) {
  // * Fire Every Second
  const intervalObs = interval(1000);

  // * Shrink intervalObs subscription
  const disposeInterval = intervalObs.pipe(take(startPoint));

  // * Fire incremental number on every second
  disposeInterval.subscribe((second) => {
    this.countDownOnRetry = startPoint - second;
  });
}