Swift中Async/Await场景下map批量获取列表详情失效如何解决
错误原因
你原代码无法执行的核心原因是:普通map转换后得到的是元素为异步函数的数组,await仅支持作用于单个异步任务,不能直接作用于整组异步调用。
简洁实现方案
方案1:Task数组包装(无需额外封装)
先为每个UUID创建独立Task让所有详情请求并行启动,再遍历await所有Task的结果即可,写法和你最初的逻辑对齐,没有多余样板代码:
Task { let list = await fetchList() // 批量创建并行任务 let detailTasks = list.map { uuid in Task { await fetchDetail(forUUID: uuid) } } // 批量获取所有任务结果 let details = await detailTasks.map { $0.value } // 此处可正常使用details结果 }
方案2:封装通用asyncMap扩展(适合高频复用)
如果项目中经常需要批量执行异步映射,可以给Sequence写扩展封装TaskGroup逻辑,后续调用更简洁:
extension Sequence { /// 支持异步转换的map,所有转换任务并行执行 func asyncMap<T>(_ transform: (Element) async -> T) async -> [T] { await withTaskGroup(of: T.self) { group in for element in self { group.addTask { await transform(element) } } var results = [T]() for await result in group { results.append(result) } return results } } /// 支持抛出异常的异步map重载 func asyncMap<T>(_ transform: (Element) async throws -> T) async rethrows -> [T] { try await withThrowingTaskGroup(of: T.self) { group in for element in self { group.addTask { try await transform(element) } } var results = [T]() for try await result in group { results.append(result) } return results } } }
封装完成后你原需求的代码可以简化为:
Task { let list = await fetchList() let details = await list.asyncMap { await fetchDetail(forUUID: $0) } }
效率说明
两种方案的执行效率和手动写withTaskGroup完全一致:所有fetchDetail请求并行执行,整体耗时为fetchList的耗时加上单个fetchDetail的耗时,没有串行请求的性能损耗。
内容的提问来源于stack exchange,提问作者Bram
相关产品推荐
相关产品推荐

