irpas技术客

PromisKit使用_ronin223

irpas 1807

promistKit主要是解决异步回调地狱的问题,举个例子,比如需要下载一个图片文件,而且这个图片文件的下载链接也需要请求,也就是先请求一个接口然后图片的下载链接,然后通过该链接去下载图片,普通做法大概就是这样:

URLSession.shared.dataTask(with: backendurl!) { data, _, error in if error != nil { print(error) return } let imageurl = String(data: data!, encoding: String.Encoding.utf8) as String! URLSession.shared.dataTask(with: URL(string:imageurl!)!) { (data, response, error) in if error != nil { print(error) return } DispatchQueue.main.async { imageView.image = UIImage(data: data!) } }.resume() }.resume()

如果再有其他操作,一层嵌套一层 的网络请求,结构很不清晰很不具有阅读性,而PromiseKit的出现就很好的解决了这个问题

Promise创建

promise包含两个回调闭包,当任务完成可以使用fulfill来回调成功信息,也可以使用reject来回调错误信息

Promise() { fulfill, reject in // code }

比如下载一个图片的请求可以这样做

func fetch(url: URL) -> Promise<Data> { return Promise { seal in URLSession.shared.dataTask(with: url!) { data, _, error in seal.resolve(data, error) }.resume() } }

当然在编程过程中也不是总会有处理错误信息的时候,可以用Guarantee创建一个没有错误信息的

Guarantee { seal in seal("Hello World") }.done { print($0) } Promise 链 then(),done(),catch()

上面我们创建了一个图片下载的promise请求,然后我们可以使用then()函数来链接,

fetch(url: <backend-url>).then { value in // value }

then()需要返回一个Promise,以此一直then,可以用done()来结束调用链,用catch()来捕获错误信息

fetch(url: <backend-url>).then { value in // value }.then {value in // value }.done {value in // value }.catch {error in //error } recover()

当然,有时候希望在发生错误前给一个默认值,可以用recover()函数

fetch(url: <imageurl>).recover { error -> Promise<UIImage> in return UIImage(name: <placeholder>) }...

因此上面图片请求例子就可以写成这样

func fetch(url: URL) -> Promise<Data> { return Promise { seal in URLSession.shared.dataTask(with: url!) { data, _, error in seal.resolve(data, error) }.resume() } } fetch(url: <backendURL>).then { data in //解析返回结果 return JSONParsePromise(data) }.then { imageurl in //下载图片文件 return fetch(url: imageurl) }.then { data in //UI赋值 imageView.image = UIImage(data: data) }.catch { error in //错误处理 }

其他链元素

firstly()

使用firstly()来作为一个链的开始

firstly { return fetch(url:url) }.then{ ... } ensure()

如果想在promise完成之前做的事情,可以使用ensure()

firstly { fetch(url: url) }.ensure { cleanup() }.catch { handle(error: $0) }

比如在请求中加入网络指示器

func fetch(url: URL) -> Promise<Data> { return Promise { seal in URLSession.shared.dataTask(with: url!) { data, _, error in seal.resolve(data, error) }.resume() } } firstly { //开始旋转 UIApplication.shared.isNetworkActivityIndicatorVisible = true return fetch(url: <backendURL>) }.then { data in return JSONParsePromise(data) // we skip the wrapping of JSONParsing }.then { imageurl in return fetch(url: imageurl) }.then { data in imageView.image = UIImage(data: data) }.ensure { //在完成之前执行 UIApplication.shared.isNetworkActivityIndicatorVisible = false }.catch { error in // in case we have an error } get()

如果想在同样的数据结果做不同的事情,可以用get()来讲任务分开

firstly { fetch(url: url) }.get { data in //… }.done { data in // 跟get数据相同,并没有发生变化 } when()

使用when来链接多个promise,当每个promise都完成时才会回调,如果其中一个promise发生错误,那么就会跳到catch处

firstly { when(fulfilled: promise1(), promise2()) }.done { result1, result2 in //… } 自定义回调线程

Promise默认的所有回调都在主线程,如果想在其他线程中处理事,可以这样做

fetch(url: url).then(on: .global(QoS: .userInitiated)) { //then closure executes on different thread } 延迟Delay let waitAtLeast = after(seconds: 0.3) firstly { fetch(url: url) }.then { waitAtLeast }.done { //… } 超时

使用race()来处理超时

let timeout = after(seconds: 4) race(when(fulfilled: fetch(url:url)).asVoid(), timeout).then { //… } 重试

网络请求不会总是成功,有时我们希望在一次失败时,再重新请求几次,那么可以使用recover().

func attempt<T>(maximumRetryCount: Int = 3, delayBeforeRetry: DispatchTimeInterval = .seconds(2), _ body: @escaping () -> Promise<T>) -> Promise<T> { var attempts = 0 func attempt() -> Promise<T> { attempts += 1 return body().recover { error -> Promise<T> in guard attempts < maximumRetryCount else { throw error } return after(delayBeforeRetry).then(on: nil, attempt) } } return attempt() } attempt(maximumRetryCount: 3) { fetch(url: url) }.then { //… }.catch { _ in // we still failed }


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #PromisKit使用