在上篇中,我谈到了可以用promise来解决Callback hell的问题,这篇我们换一种方式一样可以解决这个问题。
我们先分析一下为何promise能解决多层回调嵌套的问题,经过上篇的分析,我总结也一下几点:
1.promise封装了所有异步操作,把异步操作封装成了一个“盒子”。
2.promise提供了Monad,then相当于flatMap。
3.promise的函数返回对象本身,于是就可形成链式调用
好了,既然这些能优雅的解决callback hell,那么我们只要能做到这些,也一样可以完成任务。到这里大家可能就已经恍然大悟了,Swift就是完成这个任务的最佳语言!Swift支持函数式编程,分分钟就可以完成promise的基本功能。
一.利用Swift特性处理回调Callback hell
我们还是以上篇的例子来举例,先来描述一下场景:
假设有这样一个提交按钮,当你点击之后,就会提交一次任务。当你点下按钮的那一刻,首先要先判断是否有权限提交,没有权限就弹出错误。有权限提交之后,还要请求一次,判断当前任务是否已经存在,如果存在,弹出错误。如果不存在,这个时候就可以安心提交任务了。
那么代码如下:
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 |
func requestAsyncOperation(request : String , success : String -> Void , failure : NSError -> Void) { WebRequestAPI.fetchDataAPI(request, success : { result in WebOtherRequestAPI.fetchOtherDataAPI ( result , success : {OtherResult in [self fulfillData:OtherResult]; let finallyTheParams = self.transformResult(OtherResult) TaskAPI.fetchOtherDataAPI ( finallyTheParams , success : { TaskResult in let finallyTaskResult = self.transformTaskResult(TaskResult) success(finallyTaskResult) }, failure:{ TaskError in failure(TaskError) } ) },failure : { ExistError in failure(ExistError) } ) } , failure : { AuthorityError in failure(AuthorityError) } ) } |
接下来我们就来优雅的解决上述看上去不好维护的Callback hell。
1.首先我们要封装异步操作,把异步操作封装到Async中,顺带把返回值也一起封装成Result。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
enum Result { case Success(T) case Failure(ErrorType) } struct Async { let trunk:(Result->Void)->Void init(function:(Result->Void)->Void) { trunk = function } func execute(callBack:Result->Void) { trunk(callBack) } } |
2.封装Monad,提供Map和flatMap操作。顺带返回值也返回Async,以方便后面可以继续链式调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// Monad extension Async{ func map(f: T throws-> U) -> Async { return flatMap{ .unit(try f($0)) } } func flatMap(f:T throws-> Async) -> Async { return Async{ cont in self.execute{ switch $0.map(f){ case .Success(let async): async.execute(cont) case .Failure(let error): cont(.Failure(error)) } } } } } |
这是我们把异步的过程就封装成一个盒子了,盒子里面有Map,flatMap操作,flatMap对应的其实就是promise的then
3.我们可以把flatMap名字直接换成then, 们先分析一下为何promise能解决多层回调嵌套的问题,经过上篇的分析,我总结也一下几点:
1.promise封装了所有异步操作,把异步操作封装成了一个“盒子”。
2.promise提供了Monad,then相当于flatMap。
3.promise的函数返回对象本身,于是就可形成链式调用
好了,既然这些能优雅的解决callback hell,那么我们只要能做到这些,也一样可以完成任务。到这里大家可能就已经恍然大悟了,Swift就是完成这个任务的最佳语言!Swift支持函数式编程,分分钟就可以完成promise的基本功能。
一.利用Swift特性处理回调Callback hell
我们还是以上篇的例子来举例,先来描述一下场景:
假设有这样一个提交按钮,当你点击之后,就会提交一次任务。当你点下按钮的那一刻,首先要先判断是否有权限提交,没有权限就弹出错误。有权限提交之后,还要请求一次,判断当前任务是否已经存在,如果存在,弹出错误。如果不存在,这个时候就可以安心提交任务了。
那么代码如下:
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 |
func requestAsyncOperation(request : String , success : String -> Void , failure : NSError -> Void) { WebRequestAPI.fetchDataAPI(request, success : { result in WebOtherRequestAPI.fetchOtherDataAPI ( result , success : {OtherResult in [self fulfillData:OtherResult]; let finallyTheParams = self.transformResult(OtherResult) TaskAPI.fetchOtherDataAPI ( finallyTheParams , success : { TaskResult in let finallyTaskResult = self.transformTaskResult(TaskResult) success(finallyTaskResult) }, failure:{ TaskError in failure(TaskError) } ) },failure : { ExistError in failure(ExistError) } ) } , failure : { AuthorityError in failure(AuthorityError) } ) } |
接下来我们就来优雅的解决上述看上去不好维护的Callback hell。
1.首先我们要封装异步操作,把异步操作封装到Async中,顺带把返回值也一起封装成Result。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
enum Result { case Success(T) case Failure(ErrorType) } struct Async { let trunk:(Result->Void)->Void init(function:(Result->Void)->Void) { trunk = function } func execute(callBack:Result->Void) { trunk(callBack) } } |
2.封装Monad,提供Map和flatMap操作。顺带返回值也返回Async,以方便后面可以继续链式调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// Monad extension Async{ func map(f: T throws-> U) -> Async { return flatMap{ .unit(try f($0)) } } func flatMap(f:T throws-> Async) -> Async { return Async{ cont in self.execute{ switch $0.map(f){ case .Success(let async): async.execute(cont) case .Failure(let error): cont(.Failure(error)) } } } } } |
这是我们把异步的过程就封装成一个盒子了,盒子里面有Map,flatMap操作,flatMap对应的其实就是promise的then
3.我们可以把flatMap名字直接换成then, ="crayon-h"> TaskResult in