如何使用RxJS观测值制作倒计时计时器?
我正在努力使用可观测数据创建一个倒计时计时器,上的示例似乎不起作用。在此特定示例中,与timerInterval相关的错误不是计时器返回的可观测值的函数 我也在尝试其他方法,我想到的最好的方法是:如何使用RxJS观测值制作倒计时计时器?,rxjs,observable,reactive-programming,Rxjs,Observable,Reactive Programming,我正在努力使用可观测数据创建一个倒计时计时器,上的示例似乎不起作用。在此特定示例中,与timerInterval相关的错误不是计时器返回的可观测值的函数 我也在尝试其他方法,我想到的最好的方法是: Observable.interval(1000).take(10).subscribe(x => console.log(x)); 这里的问题是它从0数到10,我需要一个倒计时计时器,例如10,9,8…0 我也尝试过这个方法,但是对于类型Observable,计时器不存在 Observabl
Observable.interval(1000).take(10).subscribe(x => console.log(x));
这里的问题是它从0数到10,我需要一个倒计时计时器,例如10,9,8…0
我也尝试过这个方法,但是对于类型Observable,计时器不存在
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版本
您的思路是正确的-您的问题是,计时器
不存在于原型上(因此在Observable.range()
),而存在于Observable上(参见RxJS)。即
使用interval,可以指定每秒的时间长度
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))
我是take…()
情人,所以我使用takeWhile()
如下(RxJS 6.x.x,以ES6的方式)
使用timer
、scan
和takeWhile
如果不想依赖变量作为开始时间,则scan
中的第三个参数是开始编号
timer$ = timer(0, 1000).pipe(
scan(acc => --acc, 120),
takeWhile(x => x >= 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>`;
});
`;
});
输出,即:
// * 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;
});
}
这个例子对我很有用:) 顺便说一下,使用
takeWhile(val=>val>=0)
而不是take(someNumber)
可能是有道理的,但它会检查-1,然后才完成。。晚了一秒钟
下面的示例将发射10、9、8、7、6、5、4、3、2、1、0。从10开始到0结束看起来很简单,但这对我来说相当棘手
const counter$=间隔(1000);//rxjs创建操作符-将每秒触发
常数numberOfSeconds=10;
计数器$.pipe(
扫描((累加器,U电流)=>累加器-1,秒数+1),
取(秒数+1),
//可选的
完成(()=>console.log(
'当发出0且可观察对象完成时,如果您愿意,可以执行某些操作'
))
)
这将起到同样的作用:
计数器$管道(
扫描((累加器,电流)=>累加器-1,秒数),
startWith(numberOfSeconds),//扫描不会第一次运行!
取(秒数+1),
//可选的
完成(()=>console.log(
'当发出0且可观察对象完成时,如果您愿意,可以执行某些操作'
))
)
当然,你可以做很多改变。。例如,您可以在
扫描之前mapTo(-1)
,然后写入累加器+电流
,电流
将为-1。我还需要一个倒计时的间隔,因此我尝试了以下解决方案:
谢谢你的建议。它确实有效,只是感觉应该有更简单的方法来处理可观察对象。理想情况下,迭代器运算符允许倒计时,而不是只递增的范围(start,count)。希望其他人能提供一种方法。在此之前:您是否考虑过扩展Observable的原型以隐藏实现(例如)?有一个操作符可以做到这一点,
generate
它只是还没有被添加到新项目中。我在v4中看到了generate
函数,我很惊讶它不在v5中。它将为我提供所需的功能。要点:请记住,任何计时器只要不断调用timer(1000)
就会随时间推移而漂移。短时间内很好,但如果你正在编程一个时钟就不行了!如果需要精度,则需要使用系统时钟计算时间偏移。此计时器将延迟一秒结束,因为它检查-1,然后才完成。使用take(120)
而不是takeWhile()
将非常有效。
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
}
// * 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;
});
}