PromiseKit 6:如何创建多个并发 Promise 并将它们各自的结果分组到一个数组中?

Posted

技术标签:

【中文标题】PromiseKit 6:如何创建多个并发 Promise 并将它们各自的结果分组到一个数组中?【英文标题】:PromiseKit 6: How to create multiple concurrent promises and group their individual results into an array? 【发布时间】:2018-09-06 23:21:48 【问题描述】:

我正在处理一个奇怪的 API,我在其中收到一个 ID 列表,我需要单独请求每个 ID 的数据。我不需要一个接一个地链接这些请求,我只想一次获取它们,但我无法弄清楚如何以干净的方式执行此操作。

我已经制定了获取一个 ID 的方法,它会生成一个Promise<DataObject>。如何将我的 ID 数组转换为一组 promise,然后给我 [DataObject]

func fetchDataObject(_ id: Int64) -> Promise<DataObject> 
    return makeURL("\(id)")
        .then 
            URLSession.shared.dataTask(.promise, with: $0)
        .compactMap  (data, response) -> DataObject in
            // ...
            return try decoder.decode(DataObject.self, from: data)
    


// get the list of IDs and turn them into DataObjects

func fetchNew() -> Promise<[DataObject]>  // desired output
    return makeURL("all_ids").then 
        URLSession.shared.dataTask(.promise, with: $0)
        .compactMap  (data, response) -> [Int64] in
            // ...
            return try decoder.decode([Int64].self, from: data)
        .then( (ids) -> [DataObject] in
            // now what???
        )

我想我应该使用.when,但我找不到一个明确的选择来选择哪个方法签名......以及如何创建一组要传递的承诺。

【问题讨论】:

从概念上讲,您正在寻找all,但是,通过阅读FAQ,PromiseKit 将其称为when,这会将您带回CookBook 的示例。这可能只允许您传递少量请求(例如 2-3 个),但我不再使用 PromiseKit(当我第一次尝试时它有点错误)并改为移动到 Hydra 所以我我只是猜测 【参考方案1】:

这是你的答案,但按照“更清洁”的要求。

func fetchObjects() -> Promise<[DataObject]> 
    return firstly 
        makeURL("all_ids")
    .then 
        URLSession.shared.dataTask(.promise, with: $0).validate()
    .map 
        try decoder.decode([Int64].self, from: $0.data)
    .thenMap 
        self.fetchDataObject($0)
    

关键变化是thenMap,它将承诺应用于返回Promise&lt;[T]&gt;的序列的每个元素。

还使用 Swift 单行闭包语法来删除不会增加太多价值的返回值和参数名称。

firstly 让阅读链更清晰。

如果 HTTP 返回非 2xx 响应,则在 URLSession 承诺上使用 validate() 以拒绝链。

compactMap 替换为map,因为decode() 不会返回可选值。

【讨论】:

谢谢,我有不同的问题,但无法弄清楚“.thenMap”部分。你的回答也解决了我的问题!【参考方案2】:

好的,我得到了一些有用的东西,我现在更好地理解 thenwhen(fulfilled:)

您需要在您的then 中返回when

func fetchObjects() -> Promise<[DataObject]> 
    return makeURL("all_ids")
        .then 
            URLSession.shared.dataTask(.promise, with: $0)
        .compactMap  (data, response) -> [Int64] in
            // ..
            return try decoder.decode([Int64].self, from: data)
        .then  (ids) -> Promise<[DataObject]> in
            var requests: [Promise<DataObject>] = []
            for id in ids 
                requests.append(self.fetchDataObject(id))
            
            return when(fulfilled: requests)
    

【讨论】:

以上是关于PromiseKit 6:如何创建多个并发 Promise 并将它们各自的结果分组到一个数组中?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PromiseKit 6 中使用循环?

PromiseKit 手动安装

PromiseKit入门

如何使用 PromiseKit 6.3 返回 Promise<JSON>

PromiseKit 6 中 firstly 的合成器

如何使用 PromiseKit 在 Swift 3 中手动触发 Promise