使用PromiseKit实现批量API调用并等待所有响应的开发问题咨询
PromiseKit实现批量并行API调用的正确方案
你现有代码的核心问题
getURLPathsFor的封装逻辑完全不对:循环里每拿到一个url就调用一次seal.fulfill,会导致这个Promise在第一个url生成完成时就提前结束流程,根本等不到剩下的uid对应的url全部生成完。另外用可变数组在异步回调里反复append,没有线程同步保护,还容易出现数据竞争导致的数组内容错乱。- 链式调用的用法不符合PromiseKit的设计:用
thenMap处理url数组时,回调里返回的是网络请求的Promise,最终会得到Promise<[Promise<Response>]>的错误类型,根本拿不到聚合完成的请求结果。而且你在链式流程里调用的seal.fulfill(())/seal.reject(error)根本没有对应的seal定义,属于无意义的代码,本身就会引发编译或者运行错误。
正确实现方式
PromiseKit内置的*when方法*,专门用来处理"多个并行异步任务全部完成后再继续执行"的场景,完全不需要手动封装Promise、手动维护seal状态:
- 重构
getURLPathsFor方法,去掉手动的Promise初始化和数组拼接逻辑:func getURLPathsFor(_ ids: [UInt]) -> Promise<[String]> { let path = "/somePath" // 给每个uid生成单独的url获取Promise let urlPromiseList = ids.map { uid in AppConfigManager.shared.getApiUrl(path: path, uid: uid) } // 等所有url获取Promise全部成功,直接返回聚合后的url数组 return when(fulfilled: urlPromiseList) } - 调整整体链式调用逻辑,在拿到url数组后同样用
when等所有delete请求完成:let ids = [1, 2, 3, 4, 5] firstly { // 第一步:等待所有请求url生成完成 getURLPathsFor(ids) } .then { urls in // 给每个url生成单独的delete请求Promise let deleteRequestList = urls.map { url in ApiManager.shared.request(url, method: .delete) } // 等所有delete请求全部完成 return when(fulfilled: deleteRequestList) } .done { // 所有批量请求全部成功后,直接写后续业务逻辑即可,不需要手动触发resolve } .catch { error in // 流程中任意一步出错都会走到这里,直接处理错误即可,不需要手动触发reject }
实用注意点
- 仅在把不支持Promise格式的第三方异步代码转成Promise时,才需要手动初始化Promise、调用seal的fulfill/reject方法。纯链式的Promise流程本身会自动传递执行状态,手动操作seal反而容易引入bug。
when支持两种常用的执行模式,可根据业务场景选择:when(fulfilled:):只要任意一个并行任务失败,整个聚合流程就立刻终止,返回最先抛出的错误,适合"所有请求必须全部成功才算完成"的场景when(resolved:):等所有并行任务执行结束(无论成功还是失败),返回包含每个任务执行结果的数组,适合"需要拿到所有请求的执行结果,哪怕部分失败"的场景
- 不要混淆
thenMap的适用场景:thenMap用于对数组元素做同步映射,如果映射后得到的是Promise类型,必须配合when做聚合,否则会出现类型不匹配的运行错误。
内容的提问来源于stack exchange,提问作者Mihai Fischer
相关产品推荐
相关产品推荐

