Как последовательно перебирать асинхронный код в Joint

У меня есть протокол, определенный следующим образом:

protocol Prompter {
    func promptIfNeeded() async -> Bool
}

И массив Prompter соответствующих типов:

var prompters: [Prompter] { [PrompterA(), PrompterB()] }

В настоящее время я перебираю этот массив, запрашивая каждое сообщение пользователю одно за другим, используя asyncawait:

for prompter in prompters {
    let result = await prompter.promptIfNeeded()
    print("The result is \(result)")
}

Однако мне интересно использовать Combine издателей вместо asyncawait. Любые указания по этому поводу?

Примечание. Каждое приглашение должно дождаться завершения предыдущего.

Как вы хотите «задействовать» издателей? Хотите удалить все async/await из своего кода? то есть вместо этого изменить promptIfNeeded на возврат Future? Или вы хотите обернуть текущий promptIfNeeded издателем и заменить цикл for операторами объединения? Или оставить все асинхронные элементы, но использовать последовательность Bool как AnyPublisher<Bool, Never>?

Sweeper 06.05.2024 17:01

@Sweeper Я хочу удалить все async/await и использовать Future. Спасибо!

Maor 06.05.2024 17:13
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
94
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вы хотите, чтобы они выполнялись последовательно, вы можете использовать Publishers.Sequence с FlatMap с Subscribers.Demand из .max(1) . Очевидно, что метод должен будет возвращать Future. Итак, возможно:

protocol Prompter {
    func promptIfNeeded() -> Future<Bool, Never>
}

struct PrompterA: Prompter {
    func promptIfNeeded() -> Future<Bool, Never> {
        Future { promise in
            …
            promise(.success(result)) // where `result` is some `Bool`
        }
    }
}

struct PrompterB: Prompter { … }

class Foo {
    var cancellables: Set<AnyCancellable> = []
    
    func performPrompts() {
        let prompters: [Prompter] = [PrompterA(), PrompterB()]

        Publishers.Sequence(sequence: prompters)
            .flatMap(maxPublishers: .max(1)) { $0.promptIfNeeded() }
            .sink { print($0) }
            .store(in: &cancellables)
    }
}

Существуют и другие вариации на эту тему, но, надеюсь, это иллюстрирует идею: в «Комбайне» можно использовать flatMap с maxPublishers из .max(1)) для последовательного поведения.

ИМХО, я считаю, что код async-await значительно улучшает приведенный выше код, но я хотел ответить на ваш вопрос, и вы можете решить, что вы предпочитаете.

Rob 07.05.2024 00:44

Спасибо! Почему здесь вы предпочитаете async/awaitCombine?

Maor 07.05.2024 10:23

Я считаю, что цикл for гораздо более интуитивен, чем описанный выше. Использование async-await приводит к меньшему синтаксическому шуму (нет необходимости в приемниках, отменяемых значениях, фьючерсах и т. д.), имеет приятный линейный поток вместо того, чтобы полагаться на замыкания, удалять типы, подобные Result, и т. д. Комбайн был лучшей вещью, когда он был был представлен в 2019 году, но когда в 2021 году была представлена ​​параллельная обработка Swift, это несколько снизило полезность Joint. Немного необычно видеть, как кто-то просит провести рефакторинг кода параллелизма Swift в соответствии со старыми шаблонами объединения. Но, повторюсь, вы вольны использовать все, что захотите.

Rob 07.05.2024 16:14

Эй, если вы используете кодовую базу с большим количеством комбинаций и хотите, чтобы все использовало этот шаблон, тогда это здорово. Комбайн имеет более декларативную атмосферу, что делает его удобным в использовании и в кодовой базе SwiftUI. Но если у вас есть кодовая база async-await, я бы не был склонен просто реорганизовать ее для объединения без достаточно убедительных аргументов.

Rob 07.05.2024 16:14

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

Вызов метода экземпляра, изолированного от актера, в синхронном контексте, изолированном от актера
Асинхронная функция как аргумент асинхронной функции
Поддерживает ли Python numpy asyncio?
Невозможно преобразовать блок анонимного метода в делегат, поскольку некоторые возвращаемые типы в блоке не являются неявно конвертируемыми
Как получить синхронную загрузку с помощью async и ожидать в jquery загруженных метаданных?
Выполнять несколько одновременных задач (async let) и выдавать ошибку только в случае сбоя всех из них
Почему async не возвращает управление вызывающей стороне после нажатия await?
Как сохранить разблокировку пользовательского интерфейса во время обработки в WPF C#
Использование TaskCompletionSource<T> для асинхронного ожидания без блокировки?
Параллелизм с асинхронным методом: зачем мне здесь выполнять Task.Run() и можно ли этого избежать?