问题描述
我是 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()
类似,因为一旦承诺被实现,事情就会被触发在代码中移动。
由于我的学习曲线很慢,我决定开始为 iOS 15 编码并使用 Swift async/await。
问题:什么 Swift 异步/等待模式可以完成上述操作,类似于 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
}
解决方法
您可能正在寻找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
编辑:
这是我将如何返回带有评论的帖子数组。 正如你所看到的,不如 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
}
}