Swift中如何暂停多个async/await调用直至单次网络请求返回?
用Async/Await实现单次Token刷新的方案
核心思路
完全可以用类似Completion Handler的思路实现,而且必须用到Continuations——它能把回调式的网络请求转换成可等待的async函数,同时让多个等待的任务共享同一次刷新请求,避免重复调用后端接口。
具体实现步骤
- 维护两个关键状态变量:
isRefreshingToken: 布尔值,标记当前是否正在执行token刷新操作pendingContinuations: 数组,存储所有等待token刷新完成的continuation闭包
- 当任务因token过期失败时:
- 检查
isRefreshingToken状态:- 如果为
false:将其设为true,发起token刷新网络请求。请求完成后,遍历pendingContinuations用新token(或错误信息)唤醒所有等待的任务,最后清空数组并把isRefreshingToken重置为false - 如果为
true:把当前任务的continuation加入pendingContinuations队列,等待刷新完成后统一处理
- 如果为
- 检查
代码示例(Swift)
class TokenManager { private var currentToken: String? private var isRefreshingToken = false private var pendingContinuations: [(Result<String, Error>) -> Void] = [] private let lock = NSLock() // 多线程环境下保证状态安全 func getValidToken() async throws -> String { lock.lock() let hasValidToken = currentToken != nil && !isTokenExpired(currentToken!) lock.unlock() if hasValidToken { return currentToken! } return try await withCheckedThrowingContinuation { continuation in lock.lock() defer { lock.unlock() } if isRefreshingToken { // 已有刷新请求,加入等待队列 pendingContinuations.append(continuation.resume(with:)) } else { isRefreshingToken = true // 发起实际的token刷新请求 refreshToken { [weak self] result in guard let self = self else { return } self.lock.lock() defer { self.lock.unlock() } self.isRefreshingToken = false // 处理刷新结果并通知所有等待任务 switch result { case .success(let newToken): self.currentToken = newToken self.pendingContinuations.forEach { $0(.success(newToken)) } case .failure(let error): self.pendingContinuations.forEach { $0(.failure(error)) } } self.pendingContinuations.removeAll() // 唤醒当前发起请求的任务 continuation.resume(with: result) } } } } // 判断token是否过期的逻辑 private func isTokenExpired(_ token: String) -> Bool { // 这里替换成实际的过期校验逻辑 return true } // 模拟后端刷新token的网络请求 private func refreshToken(completion: @escaping (Result<String, Error>) -> Void) { DispatchQueue.global().asyncAfter(deadline: .now() + 1) { completion(.success("new_refreshed_token_2024")) } } }
关键细节
withCheckedThrowingContinuation是核心:它能让async函数暂停执行,直到我们手动调用resume方法唤醒它,完美适配回调式的网络请求- 线程安全不可少:如果是多线程环境,必须给状态变量加锁(比如示例里的
NSLock),避免并发访问导致数组越界或状态混乱 - 错误统一处理:刷新失败时,所有等待的任务都会收到同一个错误,符合业务逻辑的一致性
内容的提问来源于stack exchange,提问作者Hackerman
相关产品推荐
相关产品推荐

