PromiseKit与OMGHTTPURLRQ:请求超时的异步处理

PromiseKit与OMGHTTPURLRQ:请求超时的异步处理

【免费下载链接】PromiseKit Promises for Swift & ObjC. 【免费下载链接】PromiseKit 项目地址: https://gitcode.com/gh_mirrors/pr/PromiseKit

你是否在开发中遇到过网络请求超时导致的界面卡顿?是否为异步操作的错误处理感到头疼?本文将带你了解如何使用PromiseKit结合OMGHTTPURLRQ优雅地解决请求超时问题,让你的应用网络请求更稳定、用户体验更流畅。读完本文,你将掌握PromiseKit的超时处理机制、OMGHTTPURLRQ的基本使用以及两者结合的实战技巧。

PromiseKit的超时处理基础

PromiseKit提供了after函数来创建延迟执行的异步操作,这是实现超时处理的基础。其核心原理是通过race函数让网络请求和超时定时器竞速,谁先完成就执行对应的处理逻辑。

after函数的实现

after函数的源码位于Sources/after.swift,它接受一个时间间隔参数,返回一个在指定时间后完成的Guarantee对象:

public func after(seconds: TimeInterval) -> Guarantee<Void> {
    let (rg, seal) = Guarantee<Void>.pending()
    let when = DispatchTime.now() + seconds
    q.asyncAfter(deadline: when) { seal(()) }
    return rg
}

基本超时模式

Documentation/CommonPatterns.md中介绍了使用race实现超时的标准模式:

let fetches: [Promise<T>] = makeFetches()
let timeout = after(seconds: 4)

race(when(fulfilled: fetches).asVoid(), timeout).then {
    // 请求成功处理
}.catch { error in
    // 超时或其他错误处理
}

OMGHTTPURLRQ的请求封装

OMGHTTPURLRQ是一个轻量级的HTTP请求库,PromiseKit对其进行了扩展,使其支持Promise风格的异步调用。虽然我们无法直接获取到扩展文件,但可以推测其实现类似于其他网络库的Promise封装。

典型的请求封装方式

参照PromiseKit对其他网络库的扩展(如Alamofire),OMGHTTPURLRQ的Promise封装可能如下:

extension OMGHTTPURLRQ {
    static func dataTask(with request: URLRequest) -> Promise<Data> {
        return Promise { seal in
            let task = self.dataTask(with: request) { data, response, error in
                if let error = error {
                    seal.reject(error)
                } else if let data = data {
                    seal.fulfill(data)
                } else {
                    seal.reject(PMKError.emptyData)
                }
            }
            task.resume()
        }
    }
}

结合使用PromiseKit与OMGHTTPURLRQ处理超时

将PromiseKit的超时机制与OMGHTTPURLRQ的请求封装结合,可以构建出健壮的网络请求组件,确保在请求超时时能够及时响应并处理。

带超时的请求实现

func requestWithTimeout(url: URL, timeout: TimeInterval) -> Promise<Data> {
    // 创建网络请求Promise
    let requestPromise = OMGHTTPURLRQ.dataTask(with: URLRequest(url: url))
    
    // 创建超时Promise
    let timeoutPromise = after(seconds: timeout)
        .then { Promise<Data> { seal in
            seal.reject(PMKError.timedOut)
        }
    
    // 竞速选择先完成的Promise
    return race(requestPromise, timeoutPromise)
}

完整的使用示例

firstly {
    requestWithTimeout(url: apiURL, timeout: 5)
}.then { data in
    // 处理返回数据
    return processResponse(data: data)
}.done { result in
    // 更新UI显示结果
    updateUI(with: result)
}.catch { error in
    if error == PMKError.timedOut {
        showTimeoutAlert()
    } else {
        showError(message: error.localizedDescription)
    }
}.ensure {
    // 隐藏加载指示器
    hideLoadingIndicator()
}

超时处理流程图

mermaid

高级超时策略

除了基本的超时处理外,还可以根据实际需求实现更复杂的超时策略,提升应用的健壮性和用户体验。

指数退避重试

结合Documentation/CommonPatterns.md中的重试模式,可以实现请求超时后的指数退避重试:

func attemptRequest(with url: URL, maxRetries: Int = 3) -> Promise<Data> {
    var attempts = 0
    func attempt() -> Promise<Data> {
        attempts += 1
        let timeout = after(seconds: 5 * pow(2, Double(attempts - 1)))
        return race(OMGHTTPURLRQ.dataTask(with: URLRequest(url: url)), timeout)
            .recover { error -> Promise<Data> in
                guard attempts < maxRetries, error == PMKError.timedOut else { throw error }
                return after(seconds: pow(2, Double(attempts - 1))).then(attempt)
            }
    }
    return attempt()
}

并发请求超时控制

使用when函数可以同时处理多个请求的超时控制,确保所有请求都在指定时间内完成:

func fetchMultipleResources() -> Promise<[Data]> {
    let urls = [url1, url2, url3]
    let requests = urls.map { url in
        race(OMGHTTPURLRQ.dataTask(with: URLRequest(url: url)), after(seconds: 3))
    }
    return when(fulfilled: requests)
}

实战应用与最佳实践

在实际项目中,建议将超时处理逻辑封装为通用的网络请求工具类,统一管理超时时间、错误处理和重试策略,提高代码的可维护性和一致性。

统一的网络请求工具

class NetworkClient {
    static let shared = NetworkClient()
    private let timeout: TimeInterval = 10
    
    func request(_ url: URL) -> Promise<Data> {
        let request = OMGHTTPURLRQ.POST(url, json: ["key": "value"])
        return race(
            OMGHTTPURLRQ.dataTask(with: request),
            after(seconds: timeout).then { throw NetworkError.timeout }
        )
    }
}

enum NetworkError: Error {
    case timeout
    case invalidResponse
    // 其他错误类型
}

超时时间的合理设置

根据不同的网络环境和请求类型设置合适的超时时间:

  • 普通API请求:3-5秒
  • 大数据上传/下载:15-30秒
  • 弱网络环境:适当延长超时时间

错误处理与用户反馈

超时错误应该被明确地反馈给用户,并提供重试选项,参考Documentation/CommonPatterns.md中的错误处理建议:

.catch { error in
    if case NetworkError.timeout = error {
        showErrorView(message: "请求超时,请检查网络后重试", retryAction: { [weak self] in
            self?.fetchData()
        })
    }
}

通过PromiseKit与OMGHTTPURLRQ的结合使用,我们可以轻松实现网络请求的超时处理,避免应用因网络问题而无响应。合理运用raceafter等函数,结合重试机制和用户反馈,可以显著提升应用的稳定性和用户体验。建议你在项目中引入这种异步超时处理模式,并根据实际需求调整超时时间和重试策略,让你的应用网络请求更加健壮可靠。

【免费下载链接】PromiseKit Promises for Swift & ObjC. 【免费下载链接】PromiseKit 项目地址: https://gitcode.com/gh_mirrors/pr/PromiseKit

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值