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

如何在Swift中利用Async/Await创建HTTP请求任务栈以保证任务执行顺序

用Swift Async/Await实现串行任务队列,保证HTTP请求按用户操作顺序执行

要解决你遇到的任务并行执行、顺序混乱的问题,最直接的方案是创建一个线程安全的串行任务调度器,把所有用户触发的HTTP相关任务都加入这个调度器,让它们按加入顺序依次执行。下面是具体实现步骤:


1. 实现任务调度器(用Actor保证线程安全)

Swift的Actor天生具备线程安全特性,非常适合用来管理串行任务队列。我们可以创建一个TaskScheduler Actor,它负责维护任务队列,并逐个执行任务:

actor TaskScheduler {
    // 标记当前是否正在处理任务
    private var isProcessingTasks = false
    // 待执行的任务队列
    private var pendingTasks: [() async throws -> Void] = []
    
    /// 将任务加入队列,等待串行执行
    func enqueue(task: @escaping () async throws -> Void) async throws {
        pendingTasks.append(task)
        
        // 如果当前没有在处理任务,就启动执行流程
        if !isProcessingTasks {
            isProcessingTasks = true
            defer { isProcessingTasks = false }
            
            // 逐个执行队列中的任务
            while !pendingTasks.isEmpty {
                let nextTask = pendingTasks.removeFirst()
                try await nextTask()
            }
        }
    }
    
    /// 获取剩余待执行的任务数量(可选)
    var remainingTaskCount: Int {
        pendingTasks.count
    }
}

2. 集成到你的业务流程中

首先创建一个全局的调度器实例(或者根据需求用单例):

// 可以放在全局作用域,或者作为你的ViewModel的属性
let taskScheduler = TaskScheduler()

然后修改你的按钮点击事件,把login任务加入调度器,而不是直接启动新Task:

Button(action: {
    Task {
        do {
            try await taskScheduler.enqueue {
                try await self.login(username: username, password: password)
            }
        } catch {
            // 统一处理错误,比如弹窗提示
            print("任务执行失败:\(error)")
        }
    }
}, label: {
    Text("Login")
})

3. 为什么这个方案有效?

  • 串行执行保证顺序:调度器每次只会执行一个任务,只有当前任务完成(包括内部的所有await操作),才会执行下一个队列中的任务。不管用户点击多少次按钮,所有任务都会严格按操作顺序发送到服务器。
  • 线程安全:Actor的特性保证了enqueue方法和任务队列的访问都是线程安全的,不需要额外加锁。
  • 兼容现有代码:你不需要修改httpRequest和login的内部逻辑,只需要把任务包装后加入调度器即可。

可选:拆分任务或获取剩余任务数

如果你想把login拆成多个独立任务(比如让登录、获取用户数据、获取通知这些步骤也能和其他用户任务穿插执行),可以把每个步骤单独加入调度器:

func login(username: String, password: String) async throws {
    // 第一步:登录
    try await taskScheduler.enqueue {
        let dataCredentials = try await self.httpRequest(requestType: .login)
        let credentials = try await self.decodeData(dataCredentials)
        // 保存凭证逻辑...
    }
    
    // 第二步:获取用户数据
    try await taskScheduler.enqueue {
        let dataUserdata = try await self.httpRequest(requestType: .requestOwnUserData)
        let userdata = try await self.decodeData(dataUserdata)
        // 更新用户数据逻辑...
    }
    
    // 第三步:获取通知
    try await taskScheduler.enqueue {
        let dataNotifications = try await self.httpRequest(requestType: .requestUserNotifications)
        let notifications = try await self.decodeData(dataNotifications)
        // 更新通知逻辑...
    }
}

如果需要统计剩余任务数,只需要异步访问调度器的属性:

Task {
    let count = await taskScheduler.remainingTaskCount
    print("还有\(count)个任务待执行")
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 10:22:44