最近开发中遇到了一些场景需要这样场景,先登录、根据拿到用户 token 去请求用户信息,再根据用户信息做别的操作。一般用回调去解决,但是这个会造成回调地狱。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Alamofire.request("login").responseJSON { loginResponse in if loginResponse.result.isSuccess { Alamofire.request("userInfo").responseJSON { userInfoResponse in if userInfoResponse.result.isSuccess { Alamofire.request("friendList").responseJSON { userInfoResponse in if userInfoResponse.result.isSuccess { } else { print("friendList request failed") } } } else { print("userInfo request failed") } } } else { print("login request failed") } }
|
解决方案
主要解决方案有 RxSwift 和 PromiseKit。 如果仅仅为了解决回调地狱,建议选择 PromiseKit。具体原因请看: RxSwift vs PromiseKit
Promise 这个概念之前更多应用于 JavaScript, 主要是为了解决 JavaScript 的 Callback Hell(回调地狱) 问题。 简单来说就是, JS 中很异步函数都是用 callback 的形式返回结果,而开发者经常会连续的使用这些异步调用,最后就导致回调嵌套的层级越来越深,严重影响代码的结构和可读性。
http://swiftcafe.io/2016/07/17/promisekit/
链式调用 then
上面的回调地狱可以使用 PromiseKit 拆解成几个函数,变成线性的逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| func loadWithPromise() { login() .then { token -> Promise<String> in print("登录成功") return self.userInfo(token: token) }.then { info -> Promise<[String]> in print("获取用户信息成功") return self.friendList(info: info) }.then { list in print("获取好友列表成功") }.catch { (error) in print(error) } }
func login() -> Promise<String> { return Promise<String> { fulfill, reject in Alamofire.request("login").responseJSON { loginResponse in if loginResponse.result.isSuccess { fulfill("token") } else { reject(loginResponse.result.error!) } } } }
func userInfo(token: String) -> Promise<String> { return Promise<String> { fulfill, reject in Alamofire.request("userInfo", parameters: ["token": token]).responseJSON { loginResponse in if loginResponse.result.isSuccess { fulfill("info") } else { reject(loginResponse.result.error!) } } } }
func friendList(info: String) -> Promise<[String]> { return Promise<[String]> { fulfill, reject in Alamofire.request("friendList", parameters: ["info": info]).responseJSON { loginResponse in if loginResponse.result.isSuccess { fulfill(["a","b"]) } else { reject(loginResponse.result.error!) } } } }
|
when
经常会有这种需求,当 req1, req2 俩请求都完成后,再进行某个操作。则可以这么写:
1 2 3 4 5 6 7 8 9
| let req1 = userInfo(token: "token") let req2 = friendList(info: "info")
when(fulfilled: req1, req2) .then { data, location -> Void in }.catch { error in }
|
more
Cocoa+Promise 已经扩展了大部分 Cocoa 框架,比如 CLLocationManager
,如获取 location 并且 req1 请求结束后进行某个操作,则可以这么写:
1 2 3 4 5 6 7 8 9
| let req1 = userInfo(token: "token") let locater = CLLocationManager.promise()
when(fulfilled: req1, locater) .then { info, location in }.catch { error in }
|
更多请参考官方文档。
参考