async/await对比URLSession:新手困惑的实际优势解析
Async/Await 相较于嵌套Completion的核心优势详解
一、串行请求场景下Async/Await的额外优势
先看你当前的嵌套Completion实现:
public func example1() { NetworkingModels.shared.fetchFirstSet(completion: { events in switch events { case .success: example2() completion(.success(())) case .error(let error): Logger.logError(error) } }) } public func example2() { NetworkingModels.shared.fetchSecondSet(completion: { events in switch events { case .success: example3() completion(.success(())) case .error(let error): Logger.logError(error) } }) } public func example3() { NetworkingModels.shared.fetchThirdSet(completion: { events in switch events { case .success: completion(.success(())) case .error(let error): Logger.logError(error) } }) }
对比Async/Await的串行写法:
Task { do { try await example1() try await example2() try await example3() } catch { Logger.logError(error) } }
除了代码简洁,还有这些关键优势:
- 错误处理更集中统一:嵌套写法里错误分散在每个闭包中,容易遗漏;Async/Await可以用
do-catch一次性捕获所有请求的错误,不用在每个回调里重复写错误处理逻辑。 - 避免回调地狱的扩展性问题:如果后续要新增第4、5个请求,嵌套写法会继续加深代码层级,维护难度陡增;Async/Await只要加一行
await example4(),始终保持扁平结构。 - 线程调度自动处理:原来的Completion写法需要手动调用
DispatchQueue.main.async切回主线程,Async/Await会自动在调用的上下文恢复执行,减少线程相关的bug。 - 流程控制更直观:可以直接把异步请求的结果赋值给变量(比如
let firstData = try await example1()),后续逻辑不用嵌套在闭包里,线性的代码逻辑更符合人类思考习惯。
二、URLSession的Completion写法转Async/Await的优势
先看你当前的getHTML实现:
public func getHTML(url: String, completion: @escaping Result<String>.Completion) { guard let url = URL(string: url) else { return } var request = URLRequest(url: url) request.httpMethod = "GET" let sessionConfiguration = URLSessionConfiguration.default if let userAgent = Settings.Generic.userAgent { sessionConfiguration.httpAdditionalHeaders = ["User-Agent": userAgent] } let session = URLSession.init(configuration: sessionConfiguration) session.dataTask(with: request) {data, response, error in if error != nil { DispatchQueue.main.async { completion(.error(HTMLError.failedToExtractHTML)) } } if let data = data { if let html = String(data: data, encoding: .utf8) { completion(.success((html))) } } }.resume() }
转成Async/Await后的写法示例:
public func getHTML(url: String) async throws -> String { guard let url = URL(string: url) else { throw HTMLError.invalidURL } var request = URLRequest(url: url) request.httpMethod = "GET" let sessionConfiguration = URLSessionConfiguration.default if let userAgent = Settings.Generic.userAgent { sessionConfiguration.httpAdditionalHeaders = ["User-Agent": userAgent] } let session = URLSession(configuration: sessionConfiguration) let (data, response) = try await session.data(for: request) // 新增响应状态码校验,避免无效数据 guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { throw HTMLError.invalidResponse } guard let html = String(data: data, encoding: .utf8) else { throw HTMLError.failedToExtractHTML } return html }
关于你的疑问,具体优势如下:
- 速度不会直接提升:底层还是依赖URLSession的网络请求,耗时主要由网络环境和服务端响应决定。但Async/Await可以减少手动线程切换的冗余开销,让代码执行流程更高效。
- 可靠性显著增强:
- 避免静默失败:原来的写法中,如果数据存在但转String失败,没有调用completion,会导致调用方永远等待;Async/Await用
throws强制抛出错误,必须处理,不会出现这种无响应的情况。 - 更严谨的校验:可以轻松新增响应状态码校验等逻辑,原来的写法容易忽略这类边界情况。
- 降低内存泄漏风险:嵌套Completion容易因捕获
self导致循环引用,Async/Await不需要闭包,减少了这类内存管理问题。
- 避免静默失败:原来的写法中,如果数据存在但转String失败,没有调用completion,会导致调用方永远等待;Async/Await用
- 代码可维护性提升:
- 线性流程更易读:从创建请求到解析结果,代码从上到下执行,逻辑一目了然,不用在闭包间跳转。
- 错误处理更清晰:所有可能的错误(无效URL、网络错误、解析失败、响应异常)都通过
throws抛出,调用方用do-catch统一处理即可。 - 兼容性更好:Async/Await是Swift现代异步标准,和TaskGroup、AsyncSequence等特性兼容,后续扩展并行请求、流式处理等逻辑更方便。
内容的提问来源于stack exchange,提问作者Marcus FK
相关产品推荐
相关产品推荐

