Ответ 1
@ZahiC, классный ответ - мне нравится использование функциональной композиции в примере кода. Если позволите, я хотел бы позаимствовать его, чтобы проиллюстрировать пару дополнительных точек с использованием временных наблюдений.
Наружный, внутренний и контрольный
Все эти операторы являются операторами преобразования, такими как map()
, общей особенностью является то, что они имеют внешнюю и внутреннюю наблюдаемую. Ключевым отличием является то, как внешняя наблюдаемая контролирует внутреннюю наблюдаемую.
Чтобы сравнить их, мой пример кода запускает их попарно, выводя значения в виде [outerValue,innerValue]
. Я добавил интервалы к тесту и изменил внутреннюю задержку, чтобы произошло некоторое перекрытие по времени (используется формула delay((5-x)*200)
).
mergeMap vs concatMap
Они оба выводят все значения, разница в порядке.
mergeMap - порядок по внутренним наблюдаемым
[0,0], [1,0], [0,1], [2,0], [1,1], [3,0], [2,1], [4,0], [3, 1], [4,1]concatMap - порядок по внешним наблюдаемым
[0,0], [0,1], [1,0], [1,1], [2,0], [2,1], [3,0], [3,1], [4, 0], [4,1]
Исходя из вывода, внешний вывод mergeMap может быть задержан в последовательности, но concatMap следует строгой последовательности внешнего излучения.
SwitchMap против выхлопной карты
Они оба дросселируют выход.
switchMap - дроссельная заслонка по последнему слову
[3,0], [4,0], [4,1]выхлопная карта - сначала дроссельная заслонка
[0,0], [0,1], [4,0], [4,1]
Из выходных данных switchMap регулирует любые неполные внутренние выбросы, но выхлопные потоки следуют, пока не завершатся предыдущие.
mergeMap vs switchMap
Я добавил это, потому что switchmap часто используется в SO-ответах, где действительно следует использовать mergeMap.
mergeMap - порядок по внутренним наблюдаемым
[0,0], [1,0], [0,1], [2,0], [1,1], [3,0], [2,1], [4,0], [3, 1], [4,1]switchMap - дроссельная заслонка по последнему слову
[3,0], [4,0], [4,1]
Основной вывод заключается в том, что выход switchMap является непредсказуемым в зависимости от времени внутренней наблюдаемой, например, если внутренняя часть представляет собой http get, результаты могут зависеть от скорости соединения.
console.clear()
const { mergeMap, flatMap, concatMap, switchMap, exhaustMap, delay, map, take, toArray } = Rx.operators;
const note = {
mergeMap: 'Order by inner observable',
concatMap: 'Order by outer observable',
switchMap: 'Throttle by last',
exhaustMap: 'Throttle by first',
}
const title = (operator) => {
const opName = operator.name.replace('$1','')
return '${opName} - ${note[opName]}'
}
const display = (x) => {
return map(y => '[${x},${y}]')
}
const inner = (x) => Rx.Observable.timer(0,500)
.pipe(
delay((5-x)*200),
display(x),
take(2)
)
const example = operator => () => {
Rx.Observable.interval(500).take(5)
.pipe(
operator(x => inner(x)),
toArray(),
map(vals => vals.join(','))
)
.subscribe(x => {
console.log(title(operator))
console.log(x)
});
};
const run = (fn1, fn2) => {
console.clear()
fn1()
fn2()
}
const mmVcm = () => run(example(mergeMap), example(concatMap));
const smVem = () => run(example(switchMap), example(exhaustMap));
const mmVsm = () => run(example(mergeMap), example(switchMap));
.examples > div {
cursor: pointer;
background-color: #4CAF50;
color: white;
padding: 7px 16px;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js"></script>
<div class='examples'>
<div onClick='mmVcm()'>mergeMap vs concatMap </div>
<div onClick='smVem()'>switchMap vs exhaustMap</div>
<div onClick='mmVsm()'>mergeMap vs switchMap </div>
</div>