【Swift脑洞系列】轻松无痛实现异步操作串行

508 查看

开个新坑,来写写用 Swift 来做函数式编程的技巧。

引言:任何一个沾点 Functional 特性的框架,比如Promise,ReactiveCocoa或者RxSwift都提供了处理异步操作顺序执行的方案。
但其实用 Swift 本身自带很多Functional的特性,自己实现也并不难。
本文探讨了其中一种方法。

提起异步操作的序列执行,指的是有一系列的异步操作(比如网络请求)的执行有前后的依赖关系,前一个请求执行完毕后,才能执行下一个请求。

异步操作的定义

我们定义一般异步操作都是如下形式:

常规的异步操作都会接受一个闭包作为参数,用于操作执行完毕后的回调。

那异步操作的序列化会有什么问题呢? 看如下的伪代码:

我们定义了三个操作asyncOperation,asyncOperation1asyncOperation2,现在我们想序列执行三个操作,然后在执行完后输出 all executed。 按照常规,我们就写下了如下的代码:

可以看到,明明才三层,代码似乎就有点复杂了,而我们真正关心的代码却只有 print("all executed") 这一行。但为了遵从前后依赖的时许关系,我们不得不小心的处理回调,以防搞错层级。如果层级多了就有可能像这样:

这就是传说中的callback hell, 而且这还只是最clean的情况,实际情况中还会耦合很多的逻辑代码,更加无法维护。

用reduce来实现异步操作的串行

那是否有解决办法呢? 答案是有的。很多FRP的框架都提供了类似的实现,有兴趣的读者可以自行查看Promise、 ReactiveCocoa 和 RxSwift中的实现。

然后正如本节的标题所说,Swift提供了两个函数式的特性:

  • 函数是一等公民(可以像变量一样传来传去,可以做函数参数、返回值
  • 高阶函数,比如 mapreduce

接下来我们就用这两个特性,实现一个更加优雅的方式来做异步操作串行。

1. 定义类型

为了方便书写,我们先定义一下异步操作的类型:

AsyncFunc 代表了一个函数类型,这样的函数有一个闭包参数(其实就是上面 asyncOperation 的类型)

2. 从串行两个操作开始

我们先化简问题,假设我们只需要串行两个异步操作呢? 有没有办法把两个异步操作串行成一个异步操作呢? 想到这里,我们可以YY出这样一个函数:

concat函数,顾名思义,是连接的意思。指的是将两个异步操作:leftright串行起来,并返回一个新的异步操作。

那现在,我们来思考如何实现concat函数,既然返回的是AsyncFunc 也就是一个函数,那我们可以先YY出这样的结构: