说起Promise还在看前端同学的代码,这是一种专门针对异步数据操作编写的一套统一规则的模式,本质上,这种模式本质是通过 Promise 对象保存异步数据操作,同时 Promise 对象提供统一的异步数据操作事件处理的接口。这样,事件总线的数据订阅和数据发布事件,就可以通过 Promise 对象提供的接口实现出来。
当时还比较羡慕,觉得Promise可以大大提高代码的质量和整洁度。在iOS中当数据层异步发布数据后,可以通过 Delegate 回调给 UI 层来进行展示,但是这个只适合一对一的模式。如果异步处理完后,还需要将数据发布给其他 UI 进行处理和展示的话,就需要继续发布给其他 Delegate,从而造成 Delegate 套 Delegate 的情况。
使用 Block 和使用 Delegate 的情况类似。如果需要不断异步发布给下一个数据订阅者的话,也会出现 Block 回调嵌套其他 Block 回调的情况。一层套一层处理或者传递对于开发者是件比较头痛事情,后续维护调试起来也是极其麻烦的事情。
最近项目中的场景
// 登录第三方平台获取信息
// 请求逻辑服务器登录接口
// 保存用户信息持久化
// 查询用户的状态(例如是否弹出签到界面)
// ...
这里业务涉及到block多次嵌套,代码也比较多而且要求先后的执行顺序,虽然后期优化的时候把部分和登录业务不相干的代码通过路由分发出去,但嵌套看上去不是十分优雅。
iOS 系统里也有一对多模式的技术,比如 KVO 和 NSNotificationCenter。
使用 KVO 是强依赖属性的,只要更新了属性就会发布给所有的观察者,对应关系过于灵活,难以管控和维护。NSNotificationCenter 也有类似的问题,通过字符串来维护发布者和订阅者之间的关系,不仅可读性差,而且和 KVO 一样面临着难以管控和维护的情况。
如果用Promise的伪代码可以写成这样
firstly {
// 登录第三方平台获取信息
}.then {
// 请求逻辑服务器登录接口
}.done {
// 保存用户信息持久化}
// 查询用户的状态(例如是否弹出签到界面)
}
比以前通过 Delegate 回调处理异步事件来说更加合理,可读性也更强。
用过响应式第三方库 ReactiveCocoa 和 RxSwift的同学对这样写法一定不会陌生,但这两个库更侧重的是响应式编程,功能比较多涉及到东西比较多,对于不熟悉RAC的同学学习成本是一方面。
Promise 的概念最早是在E 语言中被提出的。C++ 11 以 std :: promise 模板形式加入到标准库中,随后出现了 CommonJS Promises/A 规范,jQuery 将这个规范实现后引入到 jQuery 1.5 版本中。
Promise 模式大受欢迎后, ECMAScript 6 将其写入了语言标准,统一了用法,并提供了原生 的 Promise 对象。 Promise 对象里保存有异步事件,Promise 的统一接口,使得其他异步操作都能够用相同的接口来处理事件。
PromiseKit for iOS
Homebrew 的作者 Max Howell 开发了 PromiseKit,将 Promise 标准带到了 iOS 中。所以,现在 iOS 上也有了小而美的事件总线技术。
romise 对象会有三种状态,分别是 pending、fulfilled、rejected:
pending 表示 Promise 对象当前正在等待异步事件处理中;
fulfilled 指的是 Promise 对象当前处理的异步事件已经成功完成;
rejected 表示 Promise 对象当前处理的异步事件没有成功。
Promise 对象还有两个重要的方法,分别是 then 和 catch。Promise 对象每次执行完 then 和 catch 方法后,这两个方法会返回先前的 Promise 对象,同时根据异步操作结果改变 Promise 对象的状态。
这里引用下GIthub的例子
then 和 catch 方法与 Promise 对象状态更改关系
执行 then 方法后返回的 Promise 对象是 rejected 状态的话,程序会直接执行 catch 方法。then 方法执行的就是订阅操作,Promise 对象触发 then 方法就是事件总线中的发布操作,then 方法执行完返回 Promise 对象能够继续同步执行多个 then 方法,由此,实现了一个发布操作对应多个订阅事件。
有了 Promise 对象后,整个异步发布和订阅操作都以同步操作的方式表现出来了。Promise 对象不仅能够避免回调层层嵌套,而且通过 Promise 的统一接口,使得事件总线的发布和订阅操作更加规范和易用。
除了 then 和 catch 方法以外,PromiseKit 还有一些好用的方法。比如 always 方法。使用了 always 方法以后, Promise 对象每次在执行方法时,都会执行一次 always 方法。
再比如 when 方法。这个方法的使用场景就是,指定多个异步操作,等这些操作都执行完成后就会执行 when 方法。when 方法类似 GCD 里面的 Dispatch Group,虽然实现的功能一样,但是代码简单了很多,使用起来也更加方便。
目前这个框架还在研究中,还有更多用法以及实例会在后续的项目优化过程中渐渐融入进去后进行更新,如果有好的想法欢迎在评论区留言,非常感谢!
值得注意的是纯OC版本尽量使用2.x以下版本,在查找资料的时候看见有blog这样提及过,2.x以上的版本需要OC&swift bridge。