You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift并发中Promise-Resolver模式的惯用Async/Await实现方案

用Swift Async/Await替代PromiseKit的单次解析Promise模式

原PromiseKit实现回顾

在PromiseKit中,我们可以创建一对Promise和解析器(Seal),用于表示一个后续会被解析的异步状态:

class ExampleClass {
    // 存储用于获取头条新闻的Promise和解析器
    private let (headlinePromise, headlineSeal) = Promise<String>.pending()
}

可以通过Promise链式调用等待状态就绪:

headlinePromise.get { headline in
    updateUI(headline: headline)
}
// 立即执行后续代码,直到Promise被解析才会调用updateUI

通过解析器触发状态完成:

makeNetworkRequest("https://news.example/headline").get { headline in
    headlineSeal.fulfill(headline)
}

一旦Promise被解析,所有等待它的代码会立即执行,且Promise只能被解析一次,后续的解析操作无效。


Swift Async/Await的地道实现

我们可以借助CheckedThrowingContinuation(或CheckedContinuation,用于无错误场景)结合Task来实现等价逻辑,完全满足要求的特性:

class ExampleClass {
    // 存储用于触发异步状态完成的continuation,仅能被调用一次
    private var headlineContinuation: CheckedContinuation<String, Error>?
    // 封装异步状态的Task,初始化时处于挂起状态
    private let headlineTask: Task<String, Error>
    
    init() {
        headlineTask = Task {
            // 挂起Task,等待外部通过continuation触发完成
            try await withCheckedThrowingContinuation { continuation in
                headlineContinuation = continuation
            }
        }
    }
    
    // 等待异步状态就绪并获取值
    func awaitHeadline() async throws -> String {
        try await headlineTask.value
    }
    
    // 标记状态为成功完成,传入结果值
    func completeHeadline(with value: String) {
        headlineContinuation?.resume(returning: value)
        headlineContinuation = nil // 置空避免重复调用
    }
    
    // 标记状态为失败,传入错误
    func failHeadline(with error: Error) {
        headlineContinuation?.resume(throwing: error)
        headlineContinuation = nil // 置空避免重复调用
    }
    
    // 模拟网络请求方法
    private func makeNetworkRequest(_ url: String) async throws -> String {
        // 实际网络请求逻辑
        return "Swift并发:用Continuation替代PromiseKit"
    }
    
    // 示例:触发网络请求并完成状态
    func fetchAndCompleteHeadline() async {
        do {
            let headline = try await makeNetworkRequest("https://news.example/headline")
            completeHeadline(with: headline)
        } catch {
            failHeadline(with: error)
        }
    }
    
    // 示例:等待状态并更新UI
    func waitForHeadlineAndUpdateUI() async throws {
        let headline = try await awaitHeadline()
        updateUI(headline: headline)
    }
    
    private func updateUI(headline: String) {
        // UI更新逻辑
        print(headline)
    }
}

特性匹配说明

  1. 声明依赖并等待状态:通过调用try await awaitHeadline(),代码会挂起直到状态被完成,无论在实例的哪个方法中都可以使用。
  2. 任意实例方法完成状态:completeHeadline(with:)和failHeadline(with:)(或者fetchAndCompleteHeadline()这类业务方法)都可以触发状态完成,完全不受调用位置限制。
  3. 状态就绪后后续代码立即执行:一旦continuation被resume,所有等待headlineTask.value的代码会立刻恢复执行;后续再调用awaitHeadline()会直接返回已缓存的结果,无需等待。
  4. 状态不可变且无法重复修改:headlineContinuation在触发后会被置空,无法再次调用resume;同时Task的结果是只读且缓存的,一旦完成就无法修改状态。

内容的提问来源于stack exchange,提问作者bdesham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 17:24:29