Должен ли я использовать "затем" или "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 Справка полезна.

Другие вопросы по тегам