Должен ли я использовать "затем" или "FlatMap" для потока управления?
Итак, я пытаюсь работать с Webflux, и у меня есть сценарий "проверь, существует ли объект; если да, сделай что-нибудь, иначе - укажи на ошибку".
Это можно записать в реакторе как:
public Mono<Void> handleObjectWithSomeId(Mono<IdType> id){
return id.
flatMap(repository::exists). //repository.exists returns Mono<Boolean>
flatMap(e -> e ? e : Mono.error(new DoesntExistException())).
then(
//can be replaced with just(someBusinessLogic())
Mono.fromCallable(this::someBusinessLogic)
);
}
или как:
public Mono<Void> handleObjectWithSomeId(Mono<IdType> id){
return id.
flatMap(repository::exists). //repository.exists returns Mono<Boolean>
flatMap(e -> e ? e : Mono.error(new DoesntExistException())).
map(e -> this.someBusinessLogic()));
}
Давайте предположим, что возвращаемый тип someBusinessLogic
не может быть изменено, и это должно быть просто void
не Mono<Void>
,
В обоих случаях, если объект не существует, соответствующий Mono.error(...)
будет произведено.
Пока я так понимаю then
а также flatMap
имеют разную семантику, фактически я получаю один и тот же результат. Хотя во втором случае я использую flatMap
против его значения, я могу пропустить flatMap
а также fromCallable
в пользу простого map
с игнорируемым аргументом (который кажется более читабельным). Моя точка зрения заключается в том, что оба приложения имеют свои преимущества и недостатки, когда речь идет о читабельности и качестве кода.
Итак, вот резюме:
Используя тогда
- профи
- семантически правильно
- минусы
- во многих случаях (как указано выше) требуется обертывание в специальном режиме Mono/Flux
Использование flatMap
- профи
- упрощает продолжение кода "счастливый сценарий"
- минусы
- семантически неверно
Каковы другие плюсы / минусы обоих подходов? Что я должен учитывать при выборе оператора?
Я обнаружил эту проблему с реактором, которая утверждает, что нет реальной разницы в скорости.
1 ответ
TL, DR: если вы заботитесь о результате предыдущего вычисления, вы можете использовать map()
, flatMap()
или другой map
вариант. В противном случае, если вы просто хотите завершить предыдущий поток, используйте then()
,
Вы можете увидеть подробный журнал выполнения для себя, разместив .log()
вызов в обоих методах:
public Mono<Void> handleObjectWithSomeId(Mono<IdType> id) {
return id.log()
.flatMap(...)
...;
}
Как и все другие операции в Project Reactor, семантика для then()
а также flatMap()
уже определены. Контекст в основном определяет, как эти операторы должны работать вместе, чтобы решить вашу проблему.
Давайте рассмотрим контекст, который вы указали в вопросе. Какие flatMap()
делает это, всякий раз, когда он получает событие, он выполняет функцию отображения асинхронно.
Так как у нас есть Mono<>
после последнего flatMap()
в этом вопросе он предоставит результат предыдущего одиночного вычисления, которое мы игнорируем. Обратите внимание, что если бы мы имели Flux<>
вместо этого вычисление будет сделано для каждого элемента.
С другой стороны, then()
не заботится о предыдущей последовательности событий. Это просто заботится о завершении события:
Вот почему в вашем примере не очень важно, какой вы используете. Однако в других контекстах вы можете выбрать соответственно.
Вы также можете найти какой оператор мне нужен? раздел Project Reactor Справка полезна.