我正在处理一个组合请求,我想在某个事件之后执行或排队执行。下面是场景-
下面是我的 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
}
}
如果有人能建议我如何处理代码的其他部分,我将不胜感激。
答案 0 :(得分:2)
如果快速连续发生多个请求,您开始使用的方法将不起作用。所有这些请求都会将 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()
}
}