带你读《2022技术人的百宝黑皮书》——响应式编程的复杂度和简化(2)https://developer.aliyun.com/article/1339638?groupCode=taobaotech
在这个接口的实现中,数据回调最简单,在没有结束的情况下,多次回调的数据可以直接回调,问题是如何保证错误和完成有且仅有一次回调,且结果回调后不再回调数据,即:
什么时候回调错误? 什么时候回调完成?
如果我们认为一个接口出错,就回调错误,这是最简单的错误处理,只需要检查和设置结束状态,在没有结束时的第一个错误进行回调即可,注意,我们需要在userInfo的请求中也做类似的处理,并保证错误回调后不再执行任何回调。
完成的回调要比错误复杂的多,我们可以来思考一下:
- 首先,我们不能在listOrders的onComplete里面取回调完成,因为这里不能代表queryUserInfo这个接口也完成了;
- 其次,我们也不能简单的通过所有queryUserInfo都完成了就回调完成,因为listOrders在完成前仍然有可能返 回新的订单数据。
也就是说,这里的完成需要在queryUserInfo进行判断,并且也需要考虑外层请求的完成情况,比普通异步接口的级联要多了两个维度。这仅仅是2种接口4次请求,在真实的编程中,接口数量会多得多,并且需要把第4点加进来,线程/队列、并发、同步、缓冲区,还要处理新数据推送响应,再考虑调试、监控、排查,复杂度显然会继续大 幅增长,保证这个过程的正确性是一件痛苦的事情。
响应式编程的复杂度使用Rx/Combine简化响应式编程
为了解决这些问题,业界搞出了Reactive Streams规范(地址:https://www.reactive-streams.org/),也出现了若干的实现,都以工具库的形式提供,包括Rx系列、Reactor,以及苹果功能类似的Combine。作为一个iOS开 发,我对RxSwift和Combine比较了解,两者主要的区别在于Combine多了一个Subscription的抽象来协调Publisher和Subscriber之间的行为,尤其是Back Pressure相关的控制,但总的来说,都提供了对于异步数据流的抽象和组合能力,用法上也很类似,这里以RxSwift为例来重写上面的过程。
第一步,实现一个将流式函数转换成Observable的工具类,这个是通用的,非常直观:
func makeObservable<Data>(f : @escaping StreamFunc<Data>) -> Observable<Data> {
2 |
|
Observable<Data>.create { observer in |
3 |
|
f { data in |
4 |
|
observer.onNext(data) |
5 |
|
} _: { error in |
6 |
|
observer.onError(error) |
7 |
|
} _: { |
8 |
|
observer.onCompleted() |
9 |
|
} |
10 |
|
return Disposables.create() |
11 |
|
} |
12 |
} |
|
第二步,针对这个例子,将listOrder和queryUserInfo转换成StreamFunc形式,listOrder本来就是Stream-
Func,对queryUserInfo进行偏应用也可以转换为StreamFunc形式,这是具体接口相关的:
func makeStreamFunc(orders : [Order], userInfoService : UserService?) -> StreamFunc<[OrderOb- ject]> { if let userInfoService = userInfoService { // 核心是对queryUserInfo的userIds参数进行偏应用 let userInfoF : StreamFunc<[OrderObject]> = { onData, onError, onComplete in let userIds = orders.map{$0.userId} userInfoService.queryUserInfo(userIds: userIds, onData: { userInfoDict in let orderObjects = orders.map { order in
8 |
|
OrderObject(order: order, userInfo: userInfoDict[order.userId]) |
9 |
|
} |
10 |
|
onData(orderObjects) |
11 |
|
}, onError: onError, onComplete: onComplete) |
12 |
|
} |
13 |
|
return userInfoF |
14 |
|
} else { |
15 |
|
return { onData, onError, onComplete in |
16 |
|
onData(orders.map{OrderObject(order: $0)}) |
17 |
|
onComplete() |
18 |
|
} |
19 |
|
} |
20 |
} |
|
带你读《2022技术人的百宝黑皮书》——响应式编程的复杂度和简化(4)https://developer.aliyun.com/article/1339635?groupCode=taobaotech