api 个请求之间的冷却时间

Cooldown between api requests

API 提供程序要求执行请求的时间不超过 1 秒。如何在我的 request 方法中使用 Combine 来实现此限制?

func request<T: Codable>(components: URLComponents) -> AnyPublisher<T, Error> {
    return urlSession.dataTaskPublisher(for: components.url!)
        .map(\.data)
        .decode(type: T.self, decoder: JSONDecoder())
        .receive(on: RunLoop.main)
        .eraseToAnyPublisher()
}

所以我想从中得到:

Request1 - 0.0 sec
Request2 - 0.3 sec
Request3 - 0.6 sec
Request4 - 0.9 sec
Request5 - 1.2 sec

...类似的东西:

Request1 - 0.0 sec
Request2 - 1.0 sec
Request3 - 2.0 sec
Request4 - 3.0 sec
Request5 - 4.0 sec

以下是您在 RxSwift 中的实现方式。 Combine 没有 concatMap 运算符,所以我不确定翻译会是什么样子。您可以在 RxCombine 库的 Combine 代码中使用以下代码。

class API {
    let urlSession: URLSession
    let subject = PublishSubject<URLRequest>()
    let result: Observable<(Event<Data>, URLRequest)>

    init(urlSession: URLSession = URLSession.shared) {
        self.urlSession = urlSession
        result = subject
            .concatMap { [urlSession] request in
                Observable.combineLatest(
                    urlSession.rx.data(request: request).materialize(),
                    Observable.just(request).delay(.seconds(1), scheduler: MainScheduler.instance).startWith(request)
                )
                .distinctUntilChanged { _, _ in true }
            }
    }

    func request<T>(request: URLRequest) -> Observable<T> where T: Decodable {
        subject.onNext(request)
        return result
            .filter { [=10=].1 == request }
            .map { [=10=].0 }
            .take(1)
            .dematerialize()
            .decode(type: T.self, decoder: JSONDecoder())
            .observe(on: MainScheduler.instance)
    }
}
extension URLSession {
    func dataTaskPublisher(url: URL, timeout: UInt32, queue: DispatchQueue) -> AnyPublisher<Data, Error> {
        return Future<Data, Error> { promise in
            queue.async {
                self.dataTask(with: url) { data, url, error in
                    if let data = data {
                        promise(.success(data))
                    }
                    if let error = error {
                        promise(.failure(error))
                    }
                }
                .resume()
                sleep(timeout)
            }
        }
        .eraseToAnyPublisher()
    }
}

用法:

let queue = DispatchQueue()

func request<T: Codable>(components: URLComponents) -> AnyPublisher<T, Error> {
    return urlSession.dataTaskPublisher(url: components.url!, timeout: 1, queue: queue)
        .decode(type: T.self, decoder: JSONDecoder())
        .receive(on: RunLoop.main)
        .eraseToAnyPublisher()
}