带你读《2022技术人的百宝黑皮书》——响应式编程的复杂度和简化(2)

简介: 带你读《2022技术人的百宝黑皮书》——响应式编程的复杂度和简化(3)

带你读《2022技术人的百宝黑皮书》——响应式编程的复杂度和简化(1)https://developer.aliyun.com/article/1339639?groupCode=taobaotech


响应式编程的复杂度

 

响应式编程的复杂度来自于4个方面:

 

可以有0次、1次或多次数据产生,也就是数据流;

除了数据之外,还有能够标识错误和完成(正常结束); 数据流和数据流、数据流和过程的组合复杂度很高;

在上面的基础上,需要处理整个过程中线程切换、并发同步、数据缓冲等问题。

 

为了支持数据流的概念,可以产生0次、1次或多次数据产生,API设计需要把数据回调和结果回调分开,通常也会把错误回调和完成回调分开,这种接口被称为流式接口,一个标准的流式接口设计如下所示:

 

1typealias Func = () -> ()
2typealias OnData<Data> = (Data) -> ()
3typealias OnError = (Error) -> ()
4typealias OnComplete = Func
5typealias StreamFunc<Data> = (@escaping OnData<Data>, @escaping OnError, @escaping OnCom- plete) -> ()

显然,流式接口是普通异步接口将一次结果向多次结果的推广,这种推广同时也增加了逻辑的复杂度。

 

我们可以通过一个逻辑上简单的例子来看一下流式接口的使用过程,为了关注于核心的复杂度,只会体现前3个方面,一方面是由于加入第4点的话会导致代码过于冗长混淆关注点,另一方面相信各位对第4点本身的复杂度和它引起的众多问题已经非常熟悉了。

 

这个例子很简单,只有三步:

 

 

  1. 假设需要为一个店铺提供一个订单展示页面,这些订单来自两个不同的平台“鹅鹅鹅”和“鸭鸭鸭”,他们各自提供了查询的接口(listOrders,为了简单假设他们提供的模型和接口完全一致);
  2. 订单列表需要展示用户的昵称等信息,需要通过对应平台的另外一个接口(queryUserInfo)查询;
  3. 由于SDK缓存、持久化、网络请求策略,数据无法一次性获取,这两个接口可能存在多次数据回调。
  4. 进一步简化问题,我们忽略变更处理、UI渲染和用户交互处理,仅仅考虑数据加载,这需要组合2个阶段的4次接口调用,先分别请求两个平台的订单,使用订单请求对应平台的userInfo,最后合并成完整数据:

 

// 数据怎么回调,什么情况结束,onError和onComplete分别在什么情况回调,保证有且仅有一次回调
func load(onData : OnData<[OrderObject]>?, onError : OnError?, onComplete : OnComplete?) {
let orderServices = [OrderService("鹅鹅鹅"), OrderService("鸭鸭鸭")]
// 记录整体请求的完成状态
var listOrderFinish = false
var queryUserFinish = false
// 记录各个请求的结果
var listOrderResults = orderServices.map{_ in false}
var queryUserResults = [Bool]()
for (index, orderService) in orderServices.enumerated() {
orderService.listOrders { orders in
// 已结束不处理
if (listOrderFinish) {
return;
  }
let index = queryUserResults.count
queryUserResults[index] = false
if let userService = getUserService(site: orderService.site){
let userIds = orders.map { order in
order.userId
  }
userService.queryUserInfo(userIds: userIds) { userInfoDict in
if (listOrderFinish && queryUserFinish) {
return;
  }
let orderObjects = orders.map { order in
OrderObject(order: order, userInfo: userInfoDict[order.userId])
  }
onData?(orderObjects)
} onError: { error in
// 如果是第一个错误,直接回调,同时标记为结束
if (!listOrderFinish || !queryUserFinish) {
listOrderFinish = true
queryUserFinish = true
onError?(error)
  }
} onComplete: {
// 外层结束,内层也结束,才是最终结束
if (!listOrderFinish || !queryUserFinish) {
queryUserResults[index] = true
// 所有都结束,回调
if (listOrderFinish && !queryUserResults.contains(false)) {
listOrderFinish = true
onComplete?()
  }
  }
  }
} else {
let orderObjects = orders.map { order in
OrderObject(order: order)


 

 

54

 

}

55

 

onData?(orderObjects)

56

 

 

57

 

queryUserResults[index] = true

58

 

// 所有都结束,回调

59

 

if (listOrderFinish && !queryUserResults.contains(false)) {

60

 

listOrderFinish = true

61

 

onComplete?()

62

 

}

63

}

 

64

} onError: { error in

65

// 如果是第一个错误,直接回调,同时标记为结束

66

if (!listOrderFinish) {

67

listOrderFinish = true

68

onError?(error)

69

}

70

} onComplete: {

71

// 注意,即使所有的请求都结束了,也不能回调结束,因为这里的结束只是代表Order请求结束,userInfo

 

请求不一定结束

72

if (!listOrderFinish) {

73

listOrderResults[index] = true

74

// 所有都结束,回调

75

if (!listOrderResults.contains(false)) {

76

listOrderFinish = true

77

}

78

}

79

}

80

 

81

}

82

}

 

 

 

带你读《2022技术人的百宝黑皮书》——响应式编程的复杂度和简化(3)https://developer.aliyun.com/article/1339637?groupCode=taobaotech

相关文章
|
Swift
带你读《2022技术人的百宝黑皮书》——响应式编程的复杂度和简化(5)
带你读《2022技术人的百宝黑皮书》——响应式编程的复杂度和简化(5)
102 0
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(4)
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(4)
116 0
|
安全
带你读《2022技术人的百宝黑皮书》——如何避免写重复代码:善用抽象和组合(4)
带你读《2022技术人的百宝黑皮书》——如何避免写重复代码:善用抽象和组合(4)
109 0
|
网络协议
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(2)
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(2)
135 1
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(5)
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(5)
117 1
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(6)
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(6)
|
SQL 缓存 JSON
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(1)
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(1)
167 1
|
算法
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(3)
带你读《2022技术人的百宝黑皮书》——性能优化之接口优化(3)
|
安全
带你读《2022技术人的百宝黑皮书》——如何避免写重复代码:善用抽象和组合(2)
带你读《2022技术人的百宝黑皮书》——如何避免写重复代码:善用抽象和组合(2)
带你读《2022技术人的百宝黑皮书》——如何避免写重复代码:善用抽象和组合(2)
|
存储 Swift 开发者
带你读《2022技术人的百宝黑皮书》——响应式编程的复杂度和简化(4)
带你读《2022技术人的百宝黑皮书》——响应式编程的复杂度和简化(4)