Swift - 排队合并请求

Posted

技术标签:

【中文标题】Swift - 排队合并请求【英文标题】:Swift - Queueing Combine Requests 【发布时间】:2021-02-26 13:18:01 【问题描述】:

我正在处理一个合并请求,我想在某个事件之后执行或排队执行。下面是场景-

    新请求已生成。 检查应用是否有访问令牌 如果是,执行请求 如果没有,获取令牌,然后执行请求

下面是我的 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 部分,我将不胜感激。

【问题讨论】:

这与您的previous question 有何不同?或者您是否希望在收到令牌之前向fetchData 发出多个请求? 我希望提出多个请求。 【参考方案1】:

如果快速连续发生多个请求,您开始使用的方法将不起作用。所有这些请求都会将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()
    

【讨论】:

以上是关于Swift - 排队合并请求的主要内容,如果未能解决你的问题,请参考以下文章

AVAudioPlayer 使用数组对音频文件进行排队 - Swift

排队UIButton的CenterYAnchor到UIPageControl Swift

[bzoj4943]蚯蚓排队

Sentinel流控-排队等待

PHP 请求“排队”

如何防止 AJAX 请求排队? [复制]