带你读《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

相关文章
|
存储 安全
VCA09AAAA0AA00 PMC-2/11/08/000/00/03/11/01/0K
VCA09AAAA0AA00 PMC-2/11/08/000/00/03/11/01/0K
210 0
|
Prometheus Kubernetes 监控
揭秘Kubernetes的秘密武器库:十大工具让你的容器编排如虎添翼!探索这些神秘而强大的工具,它们将如何彻底改变你的Kubernetes体验?
【8月更文挑战第19天】在容器世界里,Kubernetes是部署与管理容器化应用的首选平台。为了增强其功能,本文精选了十大必备工具:Helm简化复杂应用部署;Prometheus监控系统与应用指标;Grafana提供数据可视化;Fluentd统一日志管理;Envoy实现服务间通信与控制;Calico确保网络连接安全;CoreDNS提升DNS服务性能;Velero保障数据安全与迁移;Argo Workflows执行复杂工作流;Istio强化服务网格功能。这些工具覆盖部署、监控、日志等多个方面,助力提升Kubernetes的效率与稳定性。
235 3
|
存储 监控 安全
阿里云携手庆视互联数据迁云,助力全球业务升级
智能家居数据迁云,守护千万家庭安全
|
机器学习/深度学习 传感器 监控
12P3439X012/G6450081/A,KJ2003X1-BB1 VE3006
12P3439X012/G6450081/A,KJ2003X1-BB1 VE3006
116 0
|
数据可视化 前端开发 大数据
商场智能导视系统深度解析,AR与大数据融合创新商业运营模式
**商场智能导视系统提升购物体验:** 通过三维电子地图、AR导航、AR营销、VR全景导购及可视化数据,解决顾客寻路困扰,增强店铺曝光,简化招商流程,优化商场管理,借助科技创新驱动顾客满意度、品牌曝光度及运营效率的全面提升。
614 0
商场智能导视系统深度解析,AR与大数据融合创新商业运营模式
|
存储 JavaScript 前端开发
在提交代码时有哪些注意事项2
在提交代码时有哪些注意事项
120 0
在提交代码时有哪些注意事项2
|
域名解析 网络协议 网络安全
[笔记] 阿里云域名知识
[笔记] 阿里云域名知识
977 0
|
编译器 API C++
【C++ 动态库设计】动态库中的模板函数:解决如果将模板函数封装成API库
【C++ 动态库设计】动态库中的模板函数:解决如果将模板函数封装成API库
637 0
|
计算机视觉 异构计算 Python
YOLOv8改进 | 进阶实战篇 | 利用YOLOv8进行视频划定区域目标统计计数
YOLOv8改进 | 进阶实战篇 | 利用YOLOv8进行视频划定区域目标统计计数
697 0
|
存储 Java 测试技术
打印不重复的字符串全排列(递归)
本文将详细解析在生成不重复的字符串全排列时使用的Java代码。首先,我们将展示一个常规的全排列生成方法,然后介绍如何通过使用HashSet来跳过已经尝试过的字符,从而避免生成重复的全排列。最后,我们提供了一道相关的编程题目以供练习。
240 0
打印不重复的字符串全排列(递归)