【问题标题】:Swift async/await equivalent of Promise Kit "when" patternSwift async/await 相当于 Promise Kit "when" 模式
【发布时间】:2021-09-22 23:17:22
【问题描述】:

我是 Swift 新手,来自 JS,我已经开始构建一个 iOS 应用。

最初,我使用 Promise Kit 来处理异步内容,因为对我来说这比我读到的其他内容更容易。

不管怎样,在 JS 中,我经常使用以下模式:

async function doAyncFunction(item) {
  try {
    // do async call to fetch data using item
    return Promise.resolve(data);
  } catch (error) {
    return Promise.reject(error);
  }
}
const promises = items.map((item) => doAyncFunction(item));
const results = await Promise.all(promises);

我最终通过 Promise Kit 实现了这个功能:

func doManyAsyncRequests(userIds: [String], accessToken: String) -> Promise<Void> {
  Promise { seal in
    let promises = spotifyUserIds.map {
      doSingleAsyncRequest(userId: $0.id, accessToken: accessToken) // this function returns a promise
    }
    when(fulfilled: promises).done { results in
      print("Results: \(results)")
      // process results
    }.catch { error in
      print("\(error)")
      // handle error
    }
  }
}

Promise Kit 的 when 与 JavaScript 的 Promise.all() 相似之处在于,一旦实现了 Promise,就会触发事情在代码中继续进行。

由于我的学习曲线够慢,我决定开始为 iOS 15 编写代码并使用 Swift async/await。

问题:什么 Swift async/await 模式可以执行上述操作,类似于 Promise Kit 的 wait 和 JavaScript 的 Promise.all()

谢谢。

更新:感谢@workingdog,他帮助我找到了以下解决方案。我现在必须处理错误处理,但现在这是另一个主题。

func getAllThings(users: [User], accessToken: String) async -> [Thing] {
    var allThings: [Thing] = []
    await withTaskGroup(of: [Thing].self) { group in
        for user in users {
            group.async {
                let userThings = await self.getUsersThings(
                    accessToken: accessToken,
                    displayName: user.displayName,
                    userId: user.id
                )
                return userThings
            }
        }
        for await (userThings) in group {
            allThings = allThings + userThings
        }
    }
    return allThings
}

【问题讨论】:

    标签: swift promisekit ios15 swift5.5


    【解决方案1】:

    您可能正在寻找withTaskGroup(...),例如:

    func getAll() async {
        await withTaskGroup(of: Void.self) { group in
            await getPosts()
            for post in posts {
                group.async { await self.getCommentsFor(post: post) }
            }
        }
    }
    

    我已经在 github 上设置了自己的基本测试来学习这一点:https://github.com/workingDog/TestAsync

    编辑:

    这就是我如何用他们的 cmets 返回一组帖子。 如您所见,不如 getAll() 简洁。

    func getAllPosts() async -> [Post] {
        // this is the tricky parameter bit, the tuple returned when you call group.async {...}
        await withTaskGroup(of: (Int, [Comment]).self) { group in
            // get all the posts
            var thePosts: [Post] = await fetchThem()
            // for each post get all the comments (concurrently)
            for post in thePosts {
                group.async {
                    let comments: [Comment] = await self.fetchThem(with: post)
                    return (post.id, comments)
                }
            }
            // add the comments to their corresponding post (concurrently)
            for await (postid, comnts) in group {
                if let ndx = thePosts.firstIndex(where: {$0.id == postid}) {
                    thePosts[ndx].comments = comnts
                }
            }
            // when all done, return all post with their comments all cooked up
            return thePosts
        }
    }
    

    【讨论】:

    • 中介功能有必要吗?
    • 很高兴它有帮助。请注意,我根本不是专家。这对我来说也是全新的,我还在学习。我确实尝试过不使用“中间”功能,但无法使其工作。
    • 是的,我也是。这很棘手。我想做的是(使用您的示例)直接从 getAll() 中返回已解决的结果
    • 我已经编辑了我的答案,可以直接返回一组帖子。
    • 优秀的工作犬!这是for await 位我让我循环。我已将您的答案标记为解决方案,并将我的最终答案(根据您的帮助)添加到我最初编辑的问题中。谢谢!
    猜你喜欢
    • 2020-09-28
    • 2018-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-07
    • 2019-11-05
    • 2020-02-05
    相关资源
    最近更新 更多