关于react.js:响应式编程在-SAP-标准产品-UI-开发中的一个实践

2次阅读

共计 4237 个字符,预计需要花费 11 分钟才能阅读完成。

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

Jerry 在从事 SAP Commerce Cloud 前台 Angular 开发时,脑子里始终记挂着本人已经习得的 SAP UI5 开发技术。我刻意要求本人将 SAP UI5 和 Angular 各方面做比照,只心愿本人能在这两个前端开发框架上,都有肯定的技术积攒。

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

在 SAP 电商云源代码里依据关键字 CombineLatest 进行搜寻,失去 170 条搜寻后果。这阐明其在 SAP 电商云前台开发里应用是相当宽泛的。

那么这个 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 次。

我给视图控制器绑定了一个 JSON 模型,外面蕴含了 red, black, total 三个属性,别离绑定到 XML 视图的三个计数器里。当两个按钮被点击时,触发 Press 事件,对应的处理函数 onPress 被调用,在函数内更新对应计数器的值。

这个 SAP UI5 利用的实现源代码能够在这个链接取得。

再来理解如何应用响应式编程思维解决这个问题。

本文后半局部的 Angular 利用,采纳响应式编程模式实现了同样的需要,编程工具库抉择了 RxJs,一个响应式编程畛域里赫赫有名的工具库,同时也以平缓的学习曲线著称。

RxJs,全称 Reactive Extensions Library for JavaScript.

Jerry 已经录制了一个简略的视频,介绍了应用 SAP UI5 和 Angular RxJs 开发的这两个利用的运行时成果:

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

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

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

基于 RxJs 的响应式编程,外围逻辑就下图 27 ~ 39 行代码,总共 12 行 代码,行数虽少,但信息量微小。

Observable(可察看对象) 是 RxJs 响应式编程模式的外围概念,是 RxJs 对异步事件流的封装和形象。

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

有的敌人可能不太了解,引入 Observable 对象这个额定的形象层之后,仿佛没有什么用。

那就让咱们回到本文 Angular 这个例子来。

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

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

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

Observable 对象的 pipe 办法,反对传入各种操作符 (Operators),比方上图第二根横线所示的 pipe(mapTo1(1)). 这个操作的语义是,将用户点击按钮时开释出的 MouseEvent 对象,映射成常数 1. MouseEvent 对象蕴含了用户点击事件的明细,比方产生点击的工夫戳,点击时鼠标的 X 和 Y 坐标等等。然而咱们的需要仅仅是统计点击次数,所以应用 mapTo(1), 将 MouseEvent 对象映射成 1 进行计数即可。而后再应用 Scan 操作符,这个操作符接管一个累加函数作为输出值,能在其外部保护累加值,实现计数的需要。

能够把 Observable,Operator,Observable 开释的事件对象,以及订阅 Observable 的处理函数,别离类比成事实中流水线传送带上待加工的整机,以便于了解。

  • 上图左下角的数控机床:相当于 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 属性,实现界面渲染。

下图绿色虚线方框所示的联结异步事件对象,代表了用户点击 4 次 Red 按钮,3 次 Black 按钮之后,该对象开释出的 MouseEvent 和其被 Operators 解决的过程。下图底部紫色横线和蓝色的图例,代表了任意一次用户点击按钮之后,total 计数器值的计算逻辑:即以后两种按钮总的点击次数求和。

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

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

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

SAP UI5 实现函数防抖思路相似,只是须要利用开发人员自行编写防抖函数:

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

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

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

  • 按钮负责生成事件对象
  • Observable 和 Operators 负责将事件对象进行加工
  • 事件对象的订阅者对加工结束的事件对象间接进行生产

了解本文介绍的这一系列响应式编程的概念,是读懂 SAP 电商云源代码里这些令人目迷五色的 RxJs Operators 链式调用的根底。

那人笑了笑,说道:“一个人的文治分了派别,已自落了下乘。姑娘若是跟着我去,包你一新耳目,教你得悉武学别有天地。”

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

考一考大家,下面这段红色斜体文字,出自金庸哪部小说里的哪位高手?感激浏览。

更多 Jerry 的原创文章,尽在:” 汪子熙 ”:

正文完
 0