在rxjs管道中实现循环逻辑

时间:2020-02-25 15:54:11

标签: rxjs

我有一个类, QueueManager ,它管理一些队列。

QueueManager提供3个API

  • deleteQueue(queueName: string): Observable<void>
  • createQueue(queueName: string): Observable<string>
  • listQueues(): Observable<string>:可观察`

deleteQueue是一劳永逸的API,从某种意义上说,它在完成工作并删除队列后不会返回任何信号。同时createQueue如果已经存在同名队列,则会失败。

listQueues()返回由 QueueManager 管理的队列的名称。

我需要创建一个逻辑,该逻辑删除队列并重新创建它。所以我的想法是做类似的事情

  • 调用deleteQueue(queueName)方法
  • 开始一个循环,调用listQueues方法,直到返回的结果表明queueName不再存在
  • 致电createQueue(queueName)

我认为我不能使用retryrepeat运算符,因为它们重新订阅了源,在这种情况下,这意味着要多次发出deleteQueue命令,这是我需要避免的事情。

所以我想做的是像

deleteQueue(queueName).pipe(
  map(() => [queueName]),
  expand(queuesToDelete => {
    return listQueues().pipe(delay(100))  // 100 ms of delay between checks
  }),
  filter(queues => !queues.includes(queueName)),
  first() // to close the stream when the queue to cancel is not present any more in the list
)

这种逻辑似乎确实有效,但是在我看来有点笨拙。有没有更优雅的方法来解决这个问题?

1 个答案:

答案 0 :(得分:0)

需要行map(() => [queueName])是因为expand还会从其可观察的源中发出值,但我认为仅从它来看并不明显。

可以使用repeat,您只需要订阅可观察的listQueues,而不是deleteQueue

我也将延迟设置为之前 listQueues,否则,您将等待发出已经从API返回的值。

const { timer, concat, operators } = rxjs; 
const { tap, delay, filter, first, mapTo, concatMap, repeat } = operators;

const queueName = 'A';
const deleteQueue = (queueName) => timer(100);
const listQueues = () => concat(
  timer(1000).pipe(mapTo(['A', 'B'])),
  timer(1000).pipe(mapTo(['A', 'B'])),
  timer(1000).pipe(mapTo(['B'])),
);

const source = deleteQueue(queueName).pipe(
  tap(() => console.log('queue deleted')),
  concatMap(() =>
    timer(100).pipe(
      concatMap(listQueues),
      tap(queues => console.log('queues', queues)),
      repeat(),
      filter(queues => !queues.includes(queueName)),
      first()
    )
  )
);

source.subscribe(x => console.log('next', x), e => console.error(e), () => console.log('complete'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.4/rxjs.umd.js"></script>