Есть ли разница между фильтром (cond) и flatMap (x = ›cond? Of (x): EMPTY)?

Я пытаюсь понять, в чем разница между этими двумя наблюдаемыми. Единственная разница в коде заключается в следующем:

/**
* Inside rxjs pipe
*/
if(typeof x === 'number' && x > 3) {
    return of(x);
} else {
    return EMPTY;
}

vs:

.filter(typeof x === 'number' && x > 3)

Тест, который я провожу:

const a$ = from([1, 6, '4']).pipe(
            tap(console.log),
            flatMap((x) => {
                if (typeof x === 'number') {
                    if (x > 3) {
                        return of(x);
                    }
                    return EMPTY;
                }
                return EMPTY;
            }),
            tap(console.log)
        );
        const sub_a = a$.subscribe(
            (x) => { console.log(x, 'success'); done(); },
            (e) => { console.log(e, 'error'); done(); },
            () => { console.log('complete'); sub_a.unsubscribe(); done(); }
        );

а также:

        const b$ = from([2, 5, '8']).pipe(
            tap(console.log),
            filter(x => typeof x === 'number' && x > 3),
            tap(console.log)
        );
        const sub_b = b$.subscribe(
            (x) => { console.log(x, 'success'); done(); },
            (e) => { console.log(e, 'error'); done(); },
            () => { console.log('complete'); sub_b.unsubscribe(); done(); }
        );

для них обоих я получаю первое значение, зарегистрированное один раз (перед фильтром / flatMap), второе значение, зарегистрированное дважды с касаний, один раз с «завершением», а третье - один раз.

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

Я проделал то же самое с Subject, с той лишь разницей, что Subjects не испускали Complete, чего и следовало ожидать.


person Ran Lottem    schedule 28.08.2019    source источник
comment
of завершается после передачи предоставленных значений, EMPTY завершается без передачи каких-либо значений. Это не обязательно означает, что потребитель тоже должен завершить.   -  person jonrsharpe    schedule 28.08.2019
comment
Какой тест я могу написать, чтобы увидеть разницу? Результаты написанных мною тестов идентичны.   -  person Ran Lottem    schedule 28.08.2019
comment
Потому что поведение одинаковое. Как вы думаете, почему есть разница?   -  person jonrsharpe    schedule 28.08.2019
comment
Это конкретно мой вопрос - есть ли функциональная разница между filter и flatMap переходом в EMPTY.   -  person Ran Lottem    schedule 28.08.2019
comment
Я не понимаю почему это ваш вопрос, учитывая, что ваш эксперимент уже дал на него ответ (как: нет) и продемонстрировал, что flatMapping EMPTY (или, если на то пошло, of) не заставит завершиться и внешнее наблюдаемое. И почему вы с самого начала искали переопределение filter?   -  person jonrsharpe    schedule 28.08.2019
comment
Я думал, что мой тест может не охватывать функциональные возможности, которые будут вести себя иначе. Я нашел код, который превращает flatMap в EMPTY, и хотел заменить его на filter, но не был уверен, что это точно сохранит функциональность.   -  person Ran Lottem    schedule 28.08.2019
comment
Может быть разница, если Observable, возвращенный из flatMap, имеет другой планировщик, но в вашем примере видимое поведение должно быть таким же   -  person Oles Savluk    schedule 28.08.2019
comment
@OlesSavluk можешь привести пример?   -  person Ran Lottem    schedule 28.08.2019


Ответы (1)


Может быть разница, если Observable, возвращенный из flatMap, имеет другой планировщик, но в вашем примере видимое поведение должно быть таким же. Обычно это может произойти, если вы полагаетесь на побочные эффекты, которые обычно не приветствуются.

Вот пример, когда asyncScheduler изменение поведения (значения, напечатанные после создания во втором примере):

const { of, asyncScheduler, EMPTY, from } = rxjs; // = require("rxjs")
const { filter, flatMap } = rxjs.operators; // = require("rxjs/operators")

const items$ = from([1, 2, 3, 4, 5]);

console.log("------------ SYNC");
const sync$ = items$.pipe(
  filter(v => v % 2 === 0)
);
sync$.subscribe(e => console.log(e));
console.log("after sync");


console.log("------------ ASYNC");
items$.pipe(
  flatMap(v => v % 2 === 0 ? of(v, asyncScheduler) : EMPTY)
).subscribe(e => console.log(e));
console.log("after async");
<script src="https://unpkg.com/[email protected]/bundles/rxjs.umd.min.js"></script>

person Oles Savluk    schedule 28.08.2019
comment
Так может ли разница возникать только из flatMap изменения возвращаемого наблюдаемого? Если я верну его точно, две трубы идентичны? - person Ran Lottem; 28.08.2019
comment
Они не идентичны, но в большинстве случаев можно безопасно провести рефакторинг таким образом. - person Oles Savluk; 28.08.2019