我正在处理一个组合请求,我想在某个事件后执行或排队执行。下面是场景-
- 新请求生成
- 检查应用程序是否有访问令牌
- 如果是,执行请求
- 如果没有,获取令牌,然后执行请求
下面是我的API,每个请求都将被触发-
public func fetchData<T: Codable>(to request: URLRequest) -> AnyPublisher<Result<T>, Error> {
if hasToken {
return self.urlSession.dataTaskPublisher(for: request)
.tryMap(self.parseJson)
.receive(on: RunLoop.main)
.subscribe(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
else {
// Store request somewhere
// Get token
// Execute stored request
}
}
如果有人能建议我如何处理代码中的else部分,我将非常感激。
如果快速连续发生多个请求,您开始使用的方法将不起作用。所有这些请求都将hasToken
视为false
,并且它们都将发起令牌请求。
你可以创建一个var tokenRequested: Bool
属性并同步访问它。
我解决这个问题的方法——不确定这是否是最好的方法——是通过创建一个管道,所有请求都将通过该管道排队:
class Service {
private let requestToken = PassthroughSubject<Void, Error>()
private let tokenSubject = CurrentValueSubject<Token?, Error>(nil)
var c: Set<AnyCancellable> = []
init() {
requestToken.zip(tokenSubject)
.flatMap { (_, token) -> AnyPublisher<Token, Error> in
if let token = token {
return Just(token).setFailureType(to: Error.self)
.eraseToAnyPublisher()
} else {
return self.fetchToken()
.eraseToAnyPublisher()
}
}
.map { $0 as Token? }
.subscribe(tokenSubject)
.store(in: &c)
}
private func fetchToken() -> AnyPublisher<Token, Error> {
// async code to fetch the token
}
}
通过requestToken
的任何请求都与tokenSubject
的值同步,因此第一个请求与初始nil
一起使用,但随后的请求等待直到发布下一个值,当前一个完成时发生。
然后,要发出请求,您将首先获得令牌getToken()
,然后发出请求。
extension Service {
private func getToken() -> AnyPublisher<Token, Error> {
// request token, which starts queues it in the pipeline
requestToken.send(())
// wait until next token is available
return tokenSubject
.compactMap { $0 } // non-nil token
.first() // only one
.eraseToAnyPublisher()
}
func fetchData<T: Codable>(request: URLRequest) -> AnyPublisher<T, Error> {
getToken()
.flatMap { token in
// make request
}
.eraseToAnyPublisher()
}
}