The basic idea for parallel loop is to use withTaskGroup, and then addTask for each asynchronous call. The trick, though, is that one generally wants to be able to associate the responses with items in the original array (because when running concurrently, you have no assurances as to what order the responses are received). So, you might use a dictionary with the results. E.g., if your Friend object was Identifiable, you might do:
func objects(for friends: [Friend]) async -> [Friend.ID: JSObject] {
await withTaskGroup(of: (Friend.ID, JSObject).self) { group in
for friend in friends {
group.addTask { await (friend.id, FriendsPlugin.createFriendResult(friend)) }
}
// build dictionary from array of tuples
var dictionary: [Friend.ID: JSObject] = [:]
while let (index, object) = await group.next() {
dictionary[index] = object
}
// now return array of objects in the order that the friends appeared in the original array
return dictionary
}
}
Or, more concisely:
func objects(for friends: [Friend]) async -> [Friend.ID: JSObject] {
await withTaskGroup(of: (Friend.ID, JSObject).self) { group in
for friend in friends {
group.addTask { await (friend.id, FriendsPlugin.createFriendResult(friend)) }
}
return await group.reduce(into: [:]) { $0[$1.0] = $1.1 }
}
}
Alternatively, if you would simply like a [JSObject] array:
func objects(for friends: [Friend]) async -> [JSObject] {
await withTaskGroup(of: (Int, JSObject).self) { group in
for (index, friend) in friends.enumerated() {
group.addTask { await (index, FriendsPlugin.createFriendResult(friend)) }
}
// build dictionary from array of tuples
var dictionary: [Int: JSObject] = [:]
while let (index, object) = await group.next() {
dictionary[index] = object
}
// now return array of objects in the order that the friends appeared in the original array
return friends.indices.compactMap { dictionary[$0] }
}
}
Or, again, more concisely:
func objects(for friends: [Friend]) async -> [JSObject] {
await withTaskGroup(of: (Int, JSObject).self) { group in
for (index, friend) in friends.enumerated() {
group.addTask { await (index, FriendsPlugin.createFriendResult(friend)) }
}
let dictionary: [Int: JSObject] = await group.reduce(into: [:]) { $0[$1.0] = $1.1 }
return friends.indices.compactMap { dictionary[$0] }
}
}
There are many variations on the theme, but the idea is to use withTaskGroup/addTask to run the requests concurrently and then collate the results into some structure by which you can associate the responses with the items in the original array.