Используйте RxJS для очистки очереди

#rxjs

Вопрос:

Я пытаюсь очистить очередь/буфер неизвестной длины, которая ограничена пустой строкой.

Пример: in->["","P2","P1"]->out

Существует вызов, который возвращает следующий элемент в очереди. function getNext():Observable<string> Это наблюдаемое холодно и недолговечно. Так что единственное, что я мог сделать, это:

 getNext().subscribe(console.log,console.err,()=>console.log("complete"));
--> "P1"
--> "complete"
getNext().subscribe(console.log,console.err,()=>console.log("complete"));
--> "P2"
--> "complete"
getNext().subscribe(console.log,console.err,()=>console.log("complete"));
--> ""
--> "complete"
 

Я хотел бы превратить его в полукороткоживущую наблюдаемую, которая выдает значения до тех пор, пока не будет выдана пустая строка, а затем завершится.

 theBetterGetNext().subscribe(console.log,console.err,()=>console.log("complete"));
--> "P1"
--> "P2"
--> ""
--> "complete"
 

Для фиксированной длины это было бы легко. of(1,2,3).pipe(mergeMap(()=>getNext())) но я борюсь с неизвестной длиной. Не могли бы вы, пожалуйста, подвести меня к решению?

Ответ №1:

Я думаю repeatWhen , это ваш оператор:

 const theBetterGetNext = () => getNext().pipe(
  repeatWhen(value => value === "" ? EMPTY : of(null))
);

theBetterGetNext().subscribe(
  console.log,
  console.error,
  () => console.log("complete")
);
 

Это должно повторно подписаться на источник, пока значение не станет пустым (=== «»)

Редактировать: Я делаю предположение здесь: вам не нужно снова звонить getNext , чтобы получить новое значение, но вы можете повторно использовать исходное наблюдаемое…

Я просто нашел другое решение, если вам нужно позвонить getNext() :

 const theBetterGetNext = () => getNext().pipe(
  expand(value => value === "" ? EMPTY : getNext())
);

theBetterGetNext().subscribe(
  console.log,
  console.error,
  () => console.log("complete")
);
 

Комментарии:

1. Хорошо, не ОП, но расширение отлично подходит для этой проблемы.

Ответ №2:

Вы можете использовать takeWhile оператор для получения значений только в том случае, если они не являются пустой строкой.

Как только вы получите пустую строку, наблюдаемое завершится:

 of(1, 2, 3)
  .pipe(
    mergeMap(() => getNext()),
    takeWhile(val => val !== "")
  )
  .subscribe(
    console.log,
    console.error,
    () => console.log("complete")
  );
 

Комментарии:

1. похоже на то, что я хочу, но то, как вы это сделали, предполагает максимум три операции, верно? Из-за: из(1,2,3). Я мог бы использовать interval (), чтобы выдавать бесконечное количество возможностей для чтения, но я не хочу ждать во время возможностей для чтения. Есть ли что-то более подходящее тогда, интервал()?

2. хорошо, я руководствовался вашим примером, используя mergeMap . Если вам нужно постоянно звонить getNext , то expand , вероятно, это ваш лучший выбор, как предложил оливарра1.