Rxjs Возвращает первый результат двух наблюдаемых, запущенных последовательно

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

Я нашел обходной путь, но я не удовлетворен. Вы можете протестировать его здесь: тест плунжера

const first = Observable.of(10).delay(1000).do(res => console.log('first'));
const second = Observable.of(20).do(res => console.log('second'));
console.log('start');
const test = first.concatMap(ev => second.map(x=> ev)).subscribe(res => 
console.log(res));

Я думаю (и надеюсь!) Более красивое решение существует, но я не могу его найти. Заранее спасибо за вашу помощь.


person Karine    schedule 25.09.2017    source источник
comment
Я не думаю, что есть лучший способ сделать это. Единственным улучшением может быть использование ev => second.mapTo(ev), чтобы сделать его более очевидным.   -  person martin    schedule 25.09.2017


Ответы (4)


Я внутренне перевожу flatMap в then в своей голове, поэтому я ожидал увидеть что-то вроде...

const first = Observable.of(10).delay(1000).do(res => console.log('first'));
const second = Observable.of(20).do(res => console.log('second'));
const test = first.flatMap(rsp => { return second.mapTo(rsp); });

На самом деле это ничем не отличается от того, что вы опубликовали, но интуитивно это имело бы для меня больше смысла, поскольку я бы не начал думать об операции concat.

Обновлять:

Я полагаю, вы могли бы также сделать...

const test = first.delayWhen(() => second.mapTo(0));

... но я не уверен, что это более читабельно.

person Pace    schedule 25.09.2017
comment
две записи работают, но я бы хотел что-то чище, чем second.mapTo - person Karine; 26.09.2017
comment
Вы всегда можете написать свой собственный оператор или статическую функцию. Назовите это bufferUntil или delayUntil или что-то в этом роде. - person Pace; 26.09.2017

Я не уверен, но думаю, вы могли бы использовать concatMapTo. См. Пример 2. В вашем случае:

const first$ = of(10).pipe(delay(1000),tap(res => console.log('first')));
const second$ = of(20).pipe(tap(res => console.log('second')));

const test = first$.pipe(
  concatMapTo(
    second$,
    (first, second) => first
  )
);
test.subscribe(res => console.log(res));

https://stackblitz.com/edit/typescript-xrmsy5

Если вы хотите управлять большим количеством наблюдаемых, вы можете использовать switchMap/mergeMap. Например

const test = first$.pipe(
  // map(e => { if(e === '1') throw e; return e; } ), //throwing invalid result
  switchMap(e => second$, (f,s) => {console.log('switchMap',f,s); return f;}),
  switchMap(e => trird$, (f,s) => {console.log('switchMap', f,s); return f;}),
);

https://stackblitz.com/edit/typescript-mnsd8a

person Alex Walker    schedule 07.07.2018

Пользователь merge с take(1):

Observable.merge(first, second).take(1).subscribe(x=>console.log(x));
person Julia Passynkova    schedule 25.09.2017
comment
Он возвращает только второй результат. Это не то, что я хочу - person Karine; 26.09.2017

const test = first
    .pipe(
        delayWhen(() => second)
    )
    .subscribe(() => {
        ...
    });

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

person Community    schedule 09.09.2019