异步操作的可观察(主题),当其中没有重叠的异步操作时完成

时间:2017-10-09 01:26:53

标签: javascript rxjs es6-promise

我希望答案是forkJoin / Promises.all,但还有一点,请耐心等待。

我有一个承诺的来源,可以按随机顺序到达,我需要一些方式来说"当到目前为止到达的所有承诺都已完成时,让我知道"。

在基于Promise的解决方案中,我认为最初使用的是Promise.all,但承诺仍然可以#34;到达"而其他人还没有完成。有趣的是,对于一个可迭代的Promise.all"有一个很好的解决方法。在https://stackoverflow.com/a/37819138/239168

我试图以Rx的方式做这件事。在阅读了一些文档之后,我认为forkJoin是等效的Promise.all,但同样的问题,没有时间我可以安全地调用forkJoin或{{1}因为总会有另外一个被添加而另一个仍在等待...因为我现在可能没有意义,我想我会要求一些指导。

设置

(如果它很傻,请抓住你的笑声,我是Rx的新手......)

我有一个主题,我想知道它的所有承诺何时完成...它也可以随时获得新的承诺......

Promise.all

每当新承诺到达时,我只是将其添加到主题

private promiseSource = new Subject<Promise<any>>();
promises$ = this.promiseSource.asObservable();

我想要神奇地发生的事情是 - 让主题&#34;完成&#34;只要它只保留完成的承诺。

e.g。

this.promiseSource.next(somePromise);

或者换句话说,我有一个可观察到的异步操作,如果我们看一下内容,我们可以看到重叠的异步操作,我想知道什么时候没有重叠,例如

promises$.magicFlatMapForkJoinConcatMapTrickery().subscribe({
  next: x => ...,
  error: err => ...,
  complete: () => {
     console.log('all promises we got so far are done');
     // nice to have, I want this to keep "listening" for new promises
     promiseSource.youAreNotREALYCompletePleaseReset(); 
  }
});

如果这些是例如http电话,我基本上要求 - 告诉我什么时候没有打开http电话。

tl; dr

如何在RxJS世界中实现这个基于Promises的答案......

https://stackoverflow.com/a/37819138/239168

2 个答案:

答案 0 :(得分:2)

如果我正确地解释了您的问题,您只对指示是否有未决承诺的信号感兴趣。

使用mergescan来创建一个可以发出待处理承诺计数的观察点非常容易,从中你应该能够创建自己喜欢的任何信号。

基本上,每当主体发出承诺时,应该递增未决承诺的数量。每当其中一个承诺结算时,计数就会减少。

&#13;
&#13;
const promises = new Rx.Subject();

const pendingCount = Rx.Observable
  .merge(
    promises.mapTo(1),
    promises.mergeMap(p => Rx.Observable.from(p).mapTo(-1))
  )
  .scan((acc, value) => acc + value, 0)
  .do(count => console.log(`${count} pending promise(s)`));

const doneSignal = pendingCount
  .filter(count => count === 0)
  .mapTo("done");

doneSignal.subscribe(signal => console.log(signal));

const timeoutPromise = (delay) => new Promise(resolve => setTimeout(resolve, delay));

promises.next(timeoutPromise(200));
setTimeout(() => promises.next(timeoutPromise(200)), 100);
setTimeout(() => promises.next(timeoutPromise(200)), 300);
setTimeout(() => promises.next(timeoutPromise(200)), 700);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

我可以根据之前的答案想出一个相当简单的方法。您可以使用fromPromiseSubject<Promise<any>>转换为Subject<Observable<any>>,然后您可以使用this答案中描述的active功能将其降低为观察到有效的可观测量。一旦你有了这个,你就可以将你的查询短语称为&#34;当活动流数组变空时#34;这可以用一个简单的过滤器来完成,例如:

active(yourSubjectOfObservables).filter(x => x.length === 0).subscribe(() => {
    // here we are, all complete
});

每当活动流的数量转换为零时,这将触发,因此如果您只想第一次,请在过滤器和订阅之间放置.take(1)或。first

可能不是最漂亮的解决方案,但它在概念上很简单。