如何为Swift异步等待函数调用添加超时机制?
为异步等待函数添加超时的最佳方式
针对你遇到的异步函数无响应导致后续代码无法执行的问题,这里提供两种实用方案,对应不同Swift版本的需求:
Swift 5.7+ 最优方案:使用Task.withTimeout
Swift 5.7及以上版本提供了原生的超时API,直接用Task.withTimeout就能实现类似Combine的timeout操作符效果,代码简洁且原生支持:
import Foundation /// 库中不可修改的异步函数 func fetchSomething() async -> Thing? { // 模拟长时间执行逻辑 try? await Task.sleep(nanoseconds: 5_000_000_000) return Thing() } // 带超时的调用逻辑 do { // 设置2秒超时 let thing = try await Task.withTimeout(seconds: 2) { await fetchSomething() } // 异步函数成功返回,执行后续逻辑 doSomethingElse() } catch is CancellationError { // 超时触发,处理超时逻辑 print("请求超时,执行降级处理") } catch { // 处理其他可能的错误 print("请求出错:\(error)") }
逻辑说明
Task.withTimeout会在指定时间后自动取消内部任务,如果目标异步函数在超时前未完成,就会抛出CancellationError,我们可以通过捕获这个错误来执行超时后的降级逻辑,避免流程永久阻塞。
Swift 5.7以下版本:手动实现超时逻辑
如果项目还在使用较低版本的Swift,可以通过任务组实现两个任务的竞争:一个执行目标异步操作,另一个等待超时时间后触发终止,谁先完成就取谁的结果:
import Foundation /// 自定义超时包装函数 func withTimeout<T>(seconds: TimeInterval, operation: @escaping () async -> T) async throws -> T { return try await withThrowingTaskGroup(of: T.self) { group in // 添加目标异步任务 group.addTask { await operation() } // 添加超时等待任务 group.addTask { try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000)) throw CancellationError() } // 获取第一个完成的任务结果 guard let result = try await group.next() else { throw CancellationError() } // 取消剩余未完成的任务 group.cancelAll() return result } } // 使用自定义超时函数 do { let thing = try await withTimeout(seconds: 2) { await fetchSomething() } doSomethingElse() } catch is CancellationError { print("请求超时") } catch { print("请求失败:\(error)") }
注意事项
- 无论使用哪种方案,最好确保目标异步函数支持任务取消(比如内部定期检查
Task.isCancelled或调用Task.checkCancellation()),这样超时触发后原任务能及时终止,避免资源浪费。 - 如果不需要抛出错误,也可以调整包装函数返回
T?,超时返回nil,成功返回结果,适配不同的业务需求。
内容的提问来源于stack exchange,提问作者Yogurt
相关产品推荐
相关产品推荐

