rxjs:定期执行一些特定延迟的动作

时间:2018-01-12 10:15:56

标签: angular rxjs reactive-programming

客户端应用程序向服务器发送请求,这可能需要很长时间才能完成。请求完成或失败后,客户端应等待一段时间(即10秒),然后再次发送请求。

目前的工作解决方案是:

appRequest = new Subject();

ngOnInit(): void {
  this.appRequest.delay(10000).subscribe(() => this.refresh());
  this.refresh();
}

refresh() {
  this.api.getApplications().subscribe(a => {
      this.updateApplications(a);
      this.appRequest.next();
    },() => this.appRequest.next()
  );
}

对此有更优雅的解决方案吗?

修改

我可以定期使用计时器,但除非先前的请求已经完成,否则我不想发送新的请求。只有在上一个请求完成后,我才想等待10秒再次发送请求。这应该无限期重复。<​​/ em>

getApplications()函数由swagger生成,它在内部使用angular的http客户端库。目前的观察是,除非您订阅Observable返回的getApplications(),否则它不会向服务器发送请求。

5 个答案:

答案 0 :(得分:4)

repeatWhen()运算符似乎是为此设计的,但rxjs风格中缺少示例和文档。

这是RxJava的文档(描述也适用于RxJs)RxJava's repeatWhen and retryWhen, explained

  

<强>用途
  使用repeatWhen + delay定期轮询数据:
  source.repeatWhen(completed => completed.delay(5000))

您的版本可能

stopRequesting = new Subject();

ngOnInit() {
  this.api.getApplications()
    .repeatWhen(completed => completed.delay(10000))
    .takeUntil(stopRequesting)
    .subscribe(a => this.updateApplications(a))
} 

ngOnDestroy() {
  this.stopRequesting.next(true);
}

<强>演示

// log to html output
log = function(x) { document.write(x + "<br />"); };

const stop = new Rx.Subject();

Rx.Observable.interval(500)
  .take(2)
  .repeatWhen(completed => completed.delay(1000))
  .takeUntil(stop)
  .subscribe(
    x => log(`Next: ${x}`),
    err => log(`Error: ${err}`),
    () => log('Completed')
  );

setTimeout(() => stop.next(true), 10000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>

答案 1 :(得分:0)

您正在寻找interval operator

从上面的链接:

// emit value in sequence every 1 second
const source = Rx.Observable.interval(1000);
// output: 0,1,2,3,4,5....
const subscribe = source.subscribe(val => console.log(val));

答案 2 :(得分:0)

您可以使用.expand()递归调用您的函数。

var recursiveObservable = this.api.getApplications().delay(10000);

//recursively call
recursiveObservable
    .expand((res) => {
        //can do something with your res if you want to.
        return recursiveObservable;
    })
    .subscribe();

上述解决方案将:

  1. 致电this.api.getApplications()
  2. 延迟10000毫秒
  3. 重复步骤1和2
  4. 请注意,与所有递归函数一样,.expand()将无限期地重复,直到您实际为其提供终止条件。例如,您可以使用take运算符指定要重复的次数:

    recursiveObservable
        .expand((res) => {
            //can do something with your res if you want to.
            return recursiveObservable;
        })
        .take(10) //stop after 10 repetitions
        .subscribe()
    

    或者终端条件可以基于布尔值:

    var shouldContinue = true;
    
    recursiveObservable
        .expand((res) => {
            //you can modify shouldContinue based on your res results.
            return shouldContinue? recursiveObservable : Observable.empty();
        }) // will terminate when shouldContinue is false
        .subscribe()
    

答案 3 :(得分:0)

此解决方案仍使用Subject(且不止一次),但不需要其他功能来了解或致电refresh()

const retry$ = new Subject();
const autoRetryRequest$ = Observable.of('Kick start')
  .merge(retry$)
  .mergeMap(() => {
    const next$ = new Subject()

    this.api.getApplications().delay(10000).subscribe(
      value => next$.next(value),
      () => retry$.next(),
      () => retry$.next()
    );

    return next$;
  })
  .subscribe((data) => { this.updateApplications(data); });

注意:

  • 请务必使用takeUntilunsubscribe,...来阻止它。最好在takeUntil之前mergeMap
  • expand解决方案非常优雅,如果可能,应予以考虑。但在你的情况下,它不适合,因为请求必须在错误时重复,并且如果您的请求返回多个值,它将会被破坏。需要对这些案件进行特殊处理才能使其正常工作。

答案 4 :(得分:0)

repeatdelay 的解决方案看起来更容易理解:

unsubscribe = new Subject();

ngOnInit() {
  this.api.getApplications()
    .pipe(
        delay(10000),
        repeat(),
        takeUntil(this.unsubscribe))
    .subscribe(a => this.updateApplications(a))
} 

ngOnDestroy() {
  this.unsubscribe.next(true);
}