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()
}
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()
}