响应式编程在 SAP 标准产品 UI 开发中的一个实践

简介: 响应式编程在 SAP 标准产品 UI 开发中的一个实践

这是 Jerry 2021 年的第 42 篇文章,也是汪子熙公众号总共第 319 篇原创文章。


Jerry 在从事 SAP Commerce Cloud 前台 Angular 开发时,脑子里始终记挂着自己曾经习得的 SAP UI5 开发技术。我刻意要求自己将 SAP UI5 和 Angular 各方面做对比,只希望自己能在这两个前端开发框架上,都有一定的技术积累。


最近遇到 SAP 电商云前台开发的一个问题,涉及到 CombineLatest 这个操作符的用法,所以有了这篇文章。


在 SAP 电商云源代码里根据关键字 CombineLatest 进行搜索,得到 170 条搜索结果。这说明其在 SAP 电商云前台开发里使用是相当广泛的。

image.png

那么这个 CombineLatest 操作符,是应用在什么样的业务场景下呢?答案是响应式编程 (Reactive Programming) 领域。


Jerry 之前的文章,Jerry在2020 SAP全球技术大会的分享:SAP Spartacus技术介绍的文字版,曾经提到过 SAP Commerce Cloud 新一代基于开源项目 Spartacus 项目的前端界面,支持响应式 **(Responsive) **布局和自适应 **(Adaptive) **布局的特性。再加上本文的响应式 **(Reactive) **编程,这三个形容词,我刚开始接触的时候觉得很容易弄混淆。


Responsive 设计:响应式设计通过各种前端技术,为页面元素赋予了根据屏幕分辨率的变化而自动调整显示行为,以达到最佳显示效果的能力。


Adaptive 设计:为不同类别的设备分别实现不同的页面,检测到设备分辨率后调用对应的网页。


Reactive 编程:响应式编程是一种编程风格的名称,是我们解决异步和并发领域编程问题的一把利器。响应式编程通常包含事件驱动,推送机制,观察者发布者模式等特征, 本质上工作于异步数据流上。响应式编程构建出的事件反应系统具备高度的可扩展性,本文后续会通过例子给大家展示。


为了降低例子的复杂度,便于大家理解,Jerry 把之前在 SAP Commerce Cloud 中遇到的问题,抽象成一个简单的模型,分别用 SAP UI5 传统的事件处理方式,和使用 Angular RxJs 响应式编程库两种方法分别实现,大家从中可以感受差异。


首先用 SAP UI5 实现该模型。绘制一个 Red 和 一个 Black 按钮,点击后,其各自的计数器加一。同时,还有第三个计数器 Total,无论哪种按钮被点击,这个 Total 计数器也加一。


下图状态表明,当前 Red 按钮被点击 5 次,Black 按钮被点击 2 次。

image.png

image.png

这个 SAP UI5 应用的实现源代码可以在这个链接获得。


再来了解如何使用响应式编程思想解决这个问题。


本文后半部分的 Angular 应用,采用响应式编程模式实现了同样的需求,编程工具库选择了 RxJs,一个响应式编程领域里大名鼎鼎的工具库,同时也以陡峭的学习曲线著称。


RxJs,全称 Reactive Extensions Library for JavaScript.

image.png

Jerry 曾经录制了一个简单的视频,介绍了使用 SAP UI5 和 Angular RxJs 开发的这两个应用的运行时效果:


https://www.zhihu.com/zvideo/1388459864507777024


本文提到的 Angular 应用的源代码在此处下载。


下图是 Angular 应用的视图,这是一个原生的 HTML 视图,定义了两个按钮,和三个 div 标签实现的计数器。

image.png

Observable(可观察对象) 是 RxJs 响应式编程模式的核心概念,是 RxJs 对异步事件流的封装和抽象。

比较下图,传统的采取 addEventListener 实现的按钮事件订阅机制,以及基于 RxJs Observable 两种实现方式的比较。

image.png

fromEvent 操作符接收两个参数,产生事件的数据源(比如页面控件的 DOM 元素,通过 document.getElementById 返回),和事件名称 click.


fromEvent 操作符返回一个 Observable 对象,封装了异步事件源。这个异步事件源,随着用户的点击,会释放(RxJs 中的术语称为 emit) 出包含鼠标点击明细信息的 MouseEvent 事件对象。fromEvent 返回的 Observable 对象,随着时间的推移,释放出 MouseEvent 对象的行为,描述在下图第一根横线中。


横线里的 M 图例,代表 MouseEvent 对象实例,M 图例所在横线上的坐标,代表该按钮发生鼠标点击的时间戳。

image.png

上图左下角的数控机床:相当于 Observable 对象,能源源不断地释放待加工的零件,即事件对象。


流水线上的零件:相当于 Observable 对象释放的事件对象。零件会依次经过流水线上的若干机械臂 (Operators),被后者加工处理。机械臂处理后的零件,外形上有所变化,好比本文例子里的 MouseEvent,经过 mapTo(1) 处理后,变形为常量 1.


机械臂:RxJs 里众多的 Operators.


流水线终端的操作人员:给最终加工好的零件贴上标签,好比 Observable 对象的订阅者(事件对象的消费者)。


再回过头看本文 Angular 例子中的 combineLatest 操作符。它可以将任意数目的原始 Observable 对象组合起来(下图红色输入参数),返回一个新的 Observable 对象(下图蓝色输出参数),我称其为联合异步事件对象。在本文例子里,Red 按钮和 Black 按钮点击事件对应的 Observable 对象,被 combineLatest 加工,返回的联合异步事件对象,再被下图第 28 行的匿名箭头函数订阅。传入该匿名对象的输入参数 values 是一个数组,包含两个元素,值分别为当前 Red 和 Black 按钮总的点击次数。这些总的点击次数,就是通过前面描述的 Observable pipe 方法里传入的 mapTo 和 scan operator,基于按钮点击产生的 MouseEvent 加工后生成的值。而 values 数组里两个元素之和,即为当前按钮总的点击次数。因此代码 28 ~ 30 行,依次将 values 数组中的元素,赋给 red,black 和 total 三个计数器的 innerHTML 属性,完成界面渲染。

image.png

本文前面提过,基于 RxJs 构造出的响应式编程的异步事件模型,具备高度的可扩展性。假设我们按钮点击计数的需求更进一步:在一秒之内,无论客户点击多少次按钮,均只计数一次。


显然,这是一个典型的函数防抖的场景。Jerry 之前的文章,SAP UI5和Angular的函数防抖(Debounce)和函数节流(Throttle)实现原理介绍,曾经分享过 SAP UI5 如何实现函数防抖。


使用 Angular RxJs,可以更优雅地实现这个需求:在 pipe 方法里,插入一个防抖操作符 debounceTime 即可。防抖间隔为 1000 毫秒,语义是,无论用户在 1 秒之内快速点击多少次按钮,Observable 对象只会发送 1 个 MouseEvent 对象,给 debounceTime 后续的操作符,即 mapTo(1).

image.png

最后,总结一下在这个具体的统计按钮点击次数的例子里,响应式编程从程序设计的角度讲,究竟体现出了什么优势。


按钮是生产者,是产生的 MouseEvent 的数据源,用户的点击动作,触发了 MouseEvent 的产生。按钮点击事件处理函数,相当于 MouseEvent 的消费者。在 SAP UI5 实现的消费者代码里,除了编写把计数器最新值刷新到 UI 的逻辑之外,还负责维护计数器的累加值。这就好比现实中流水线终端的工人,既要负责给零件贴标签,又要负责对零件进行加工。这种做法一定程度上违反了单一职责 (Single Responsibility) 和关注点分离原则 (Seperation of Concerns).

image.png

最理想的情况,就是像 Angular RxJs 那样,引入 Observable 及 Operators 这一中间层,这样三种角色各司其职,职责清晰:


按钮负责生成事件对象

Observable 和 Operators 负责将事件对象进行加工

事件对象的订阅者对加工完毕的事件对象直接进行消费

理解本文介绍的这一系列响应式编程的概念,是读懂 SAP 电商云源代码里这些令人眼花缭乱的 RxJs Operators 链式调用的基础。

image.png

Jerry 之前用 SAP UI5 做前端开发,从去年接触了 Angular 之后,也有了“前端开发别有天地”的感受。

考一考大家,上面这段红色斜体文字,出自金庸哪部小说里的哪位高手?感谢阅读。

相关文章
|
1月前
|
人工智能 搜索推荐 Serverless
使用金庸的著作,来测试阿里通义千问最新开放的长文档处理功能
使用金庸的著作,来测试阿里通义千问最新开放的长文档处理功能
88 7
使用金庸的著作,来测试阿里通义千问最新开放的长文档处理功能
|
1月前
|
前端开发 编解码 数据格式
浅谈响应式编程在企业级前端应用 UI 开发中的实践
浅谈响应式编程在企业级前端应用 UI 开发中的实践
24 0
浅谈响应式编程在企业级前端应用 UI 开发中的实践
|
1天前
UI开发第四篇——实现像handcent sms或者chomp sms那样的气泡
UI开发第四篇——实现像handcent sms或者chomp sms那样的气泡
|
11天前
|
前端开发 测试技术 持续交付
【Flutter 前端技术开发专栏】Flutter 中的 UI 测试与自动化测试
【4月更文挑战第30天】本文探讨了 Flutter 应用中UI测试和自动化测试的重要性,包括保障质量、提高效率和增强开发信心。Flutter提供`flutter_test`库进行Widget测试,以及`flutter_driver`进行集成测试。UI测试涵盖界面布局、交互和状态变化的验证,最佳实践建议尽早引入测试、保持用例简洁,并结合手动测试。未来,随着Flutter技术发展,UI测试和自动化测试将更加完善,助力开发高质量应用。
【Flutter 前端技术开发专栏】Flutter 中的 UI 测试与自动化测试
|
11天前
|
前端开发 搜索推荐 UED
【Flutter前端技术开发专栏】Flutter中的高级UI组件应用
【4月更文挑战第30天】探索Flutter的高级UI组件,如`TabBar`、`Drawer`、`BottomSheet`,提升应用体验和美观度。使用高级组件能节省开发时间,提供内置交互逻辑和优秀视觉效果。示例代码展示了如何实现底部导航栏、侧边导航和底部弹出菜单。同时,自定义组件允许个性化设计和功能扩展,但也带来性能优化和维护挑战。参考Flutter官方文档和教程,深入学习并有效利用这些组件。
【Flutter前端技术开发专栏】Flutter中的高级UI组件应用
|
1月前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。
|
1月前
|
数据库
SAP CRM产品主数据无法根据产品描述字段进行搜索的原因
SAP CRM产品主数据无法根据产品描述字段进行搜索的原因
17 5
|
1月前
什么是 SAP ABAP 里的 Subscreen
什么是 SAP ABAP 里的 Subscreen
16 1
什么是 SAP ABAP 里的 Subscreen
|
2月前
|
前端开发 搜索推荐 开发者
SAP UI5 sap.m.Column 控件的 minScreenWidth 属性介绍
SAP UI5 sap.m.Column 控件的 minScreenWidth 属性介绍
32 0
|
2月前
|
JavaScript 前端开发 开发者
SAP UI5 控件 sap.m.ListBase 的 inset 属性的作用介绍
SAP UI5 控件 sap.m.ListBase 的 inset 属性的作用介绍
17 0