Swift/Combine环境下顺序执行两个Future异步任务的实现方案
实现方案
优化API签名后的优雅实现(推荐)
原有嵌套Result的写法没有利用Combine原生的错误处理能力,小幅调整签名后代码更简洁易维护,也完全满足顺序执行的需求。
调整后的函数签名
import Combine func firstCall() -> Future<Void, Error> { return Future { promise in // 成功走.success,失败走.failure即可 promise(.success(())) } } func secondSynchronousCall() throws { // 原有同步逻辑 } private func secondCall() -> Future<Void, Error> { return Future { [weak self] promise in guard let self = self else { promise(.failure(NSError(domain: "InstanceReleased", code: -1, userInfo: nil))) return } do { try self.secondSynchronousCall() promise(.success(())) } catch { promise(.failure(error)) } } }
工具方法实现
// 按顺序执行任务队列,前一个成功才执行下一个 func executeInSequence<T, E: Error>(_ publishers: [AnyPublisher<T, E>]) -> AnyPublisher<T, E> { return publishers.dropFirst().reduce(into: publishers.first?.eraseToAnyPublisher()) { result, next in result = result?.flatMap { _ in next }.eraseToAnyPublisher() } ?? Empty().eraseToAnyPublisher() } // 扩展统一结果回调入口 extension Publisher where Output == Void, Failure == Error { func onResult(_ callback: @escaping (Result<Void, Error>) -> Void) -> AnyCancellable { return self.sink( receiveCompletion: { completion in if case .failure(let err) = completion { callback(.failure(err)) } }, receiveValue: { callback(.success(())) } ) } }
调用示例
完全匹配你期望的调用形式,注意需要持有返回的AnyCancellable避免订阅提前释放:
var cancellable: AnyCancellable? cancellable = executeInSequence([ firstCall().eraseToAnyPublisher(), secondCall().eraseToAnyPublisher() ]) .onResult { finalResult in print(finalResult) }
兼容原有签名的实现(不修改现有函数)
如果不需要调整原有Future<Result<Void, Error>, Never>的签名,可以直接用以下实现:
工具方法实现
import Combine typealias AsyncCall = Future<Result<Void, Error>, Never> func executeInSequence(_ calls: [AsyncCall]) -> AnyPublisher<Result<Void, Error>, Never> { return calls.dropFirst().reduce(into: calls.first?.eraseToAnyPublisher()) { result, next in result = result?.flatMap { prevResult -> AnyPublisher<Result<Void, Error>, Never> in // 前序调用失败直接返回错误,不执行后续任务 if case .failure(let err) = prevResult { return Just(.failure(err)).eraseToAnyPublisher() } // 前序调用成功才执行下一个 return next.eraseToAnyPublisher() }.eraseToAnyPublisher() } ?? Just(.success(())).eraseToAnyPublisher() } extension Publisher where Output == Result<Void, Error>, Failure == Never { func onResult(_ callback: @escaping (Result<Void, Error>) -> Void) -> AnyCancellable { return self.sink(receiveValue: callback) } }
调用示例
和你给出的示例完全一致:
var cancellable: AnyCancellable? cancellable = executeInSequence([firstCall(), secondCall()]) .onResult { finalResult in print(finalResult) }
内容的提问来源于stack exchange,提问作者Richard Topchii
相关产品推荐
相关产品推荐

