处理相互依赖的并发http请求

Deal with concurrent http requests that depend on each other

所以,我有一个复杂的数据要获取,它涉及 4 个请求,每个请求都取决于最后一个请求的结果,然后 returns 中的一些是一个列表,因此对于该列表中的每个元素,我必须得到一些信息。

上下文

我正在使用 YouTube API,我必须获取的数据是用户订阅的频道发送的最新视频列表。

这是执行此操作所需的请求:

[1]: Returns 用户订阅的频道列表。 return 大小配置为 5,因此我必须重复此请求,直到获取所有订阅的频道

[2]: Returns 特定频道已发送视频播放列表的 id

[3]: Returns n 个特定频道的最后一个视频

[4]:Returns 特定视频的信息

第一次尝试

一开始我是同步获取数据的,就是执行request[1],直到所有channel都取完。然后,我遍历频道列表,并为每个频道执行请求 [2] 以获取播放列表的 ID。然后请求 [3] 获取 n 个视频,对于每个视频,使用请求 [4] 获取其信息。

问题

问题是 return 向用户发送视频需要很长时间,所以我想到了并行执行请求。问题是我需要知道所有请求何时完成 运行,才能按日期重新排序视频列表。为此,我的代码到处都是 DispatchGroup 的复杂混乱。

所以,简而言之,处理这样的问题的最佳方法是什么,我有各种相互依赖的请求,我想并行执行其中的一些(第二个 - 我必须为每个通道执行)并且需要知道何时完成。

使用DispatchGroup。 DispatchGroup是iOS中的一个"component",可以对一些相关操作进行分组,必须等待。

这里不能直接使用,为什么?因为 URLSession 本身将 web 操作发布在不同于发起者的后台线程上,所以我们必须手动 enterleave。当运算次数为0时,group.wait returns.

此代码不是最佳设计模式。但这仅演示了在简单设计模式中可以完成的工作。

import UIKit

class URLRequestGroup {

    var dispatchGroup: DispatchGroup

    init(dispatchGroup: DispatchGroup) {
        self.dispatchGroup = dispatchGroup
    }

    init() {
        self.dispatchGroup = DispatchGroup()
    }

    func beginURLRequest(urlRequest: URLRequest,
                         completionHandler: @escaping (Data?, URLResponse?, Error?) -> ()) {

        let urlSession = URLSession(configuration: URLSessionConfiguration.default)
        // Enter the dispatchGroup manually
        dispatchGroup.enter()
        urlSession.dataTask(with: urlRequest, completionHandler: { [weak self] data, urlResponse, error in

            completionHandler(data, urlResponse, error)
            // Leave this dispatchGroup.
            self?.dispatchGroup.leave()
        }).resume()

    }

}

let group = URLRequestGroup()
group.beginURLRequest(urlRequest: URLRequest(url: URL(fileURLWithPath: "http://www.example.com")), completionHandler: { data, urlResponse, error in

    print(data?.count ?? 0)
})
// Put any other request here.
group.dispatchGroup.wait()

所以,我一直在努力尝试使用 NSURLSession 来组织这个复杂的请求过程,但我无法得到我想要的代码。

为了更容易使用,我使用了 Just,这使我能够以更简单、更清晰和容易的方式执行这些请求。

另一种选择是使用 PromiseKit, which easily allows chaining of requests.

NSURLSession 包装在承诺上