共计 3517 个字符,预计需要花费 9 分钟才能阅读完成。
这是 Jerry 2021 年的第 9 篇文章,也是汪子熙公众号总共第 280 篇原创文章。
本文 Jerry 本来写于 2016 年 5 月,过后公布于团队外部 wiki.
五年过后,Jerry 应用的开发框架,从 SAP UI5 变成了 Angular.
最近 Jerry 在做 SAP Spartacus 开发时,遇到了和本文形容极为相似的场景。因为我学习新常识的时候,总喜爱把之前曾经相熟的常识拿来做横向类比,所以本文首先重温一个不少 SAP UI5 开发人员都了解得似是而非的知识点,为后续的分享做一个铺垫。
本公众号后续的文章,会介绍如何在 Angular 技术栈里,应用 RxJS 优雅地解决此类问题。
RxJS 是 Jerry 之前的文章 Jerry 在 2020 SAP 寰球技术大会的分享:SAP Spartacus 技术介绍的文字版 已经提到的,一个 Angular 重度依赖的基于 Observables 的响应式编程库。
本文余下的局部,咱们从新回到 SAP UI5 的世界。
My Opportunities 是 SAP 成都研究院 CRM Fiori 开发团队于 2014 年到 2016 年之间,负责的 CRM Fiori 利用之一。用户在创立 Opportunity 时,须要指定 Account 字段,该字段反对 Live Search 性能,比方敲入一个字符 ”J”, UI5 会发送一个 OData 申请到后盾,后者异步返回 Account 模型里 fullname 字段蕴含 J 的那些数据,作为搜寻后果,通过下拉列表的形式显示在 UI 上:
OData 申请 url:
/sap/opu/odata/sap/CRM_OPPORTUNITY/AccountCollection?$top=10&$filter=substringof(%27J%27,fullName)&sap-client=001&$expand=MainAddress&$select=accountID,MainAddress/city,MainAddress/country,fullName
以此类推,如果在字符 J 前面再敲一个 e,会触发一个新的 OData 申请,依据 ”Je” 搜寻:
/sap/opu/odata/sap/CRM_OPPORTUNITY/AccountCollection?$top=10&$filter=substringof(%27Je%27,fullName)&sap-client=001&$expand=MainAddress&$select=accountID,MainAddress/city,MainAddress/country,fullName
过后组内有共事察看到一个景象:如果用户疾速输出一连串字符,则在 Chrome 开发者工具 Network 标签页里,从工夫程序上来说,先触发的 OData 申请,状态会被标注为 canceled:
基于这个察看后果,有共事做出了这样的猜想:
极短时间内发送两个 OData 申请,则第一个会主动被 cancel 掉。
这个猜想即使纯正从字面意义上讲,也有两点值得斟酌之处:
(1)“极短时间”,多短算极短?1 毫秒?1 微秒?
(2) OData 申请被谁 cancel 掉?UI5 框架还是浏览器?
为了验证这个猜想是否正确,我写了一段简略的测试代码:在一个 for 循环里应用 SAP UI5 OData Model read API,收回 10 个 OData 申请:
测试发现,无论是同步还是异步申请,都未呈现被 cancel 的状况。
10 个同步申请的执行状况如下图所示:同 Timeline 序列栏能够看到,10 个同步申请按工夫程序,被后盾解决,再顺次收到响应。
10 个异步申请的执行状况:10 个申请简直同时收回,同时收到响应。
测试结果表明,这个猜想“极短时间内发送两个 OData 申请,则第一个会主动被 cancel 掉”不成立。
然而咱们在 Chrome 开发者工具里,的确察看到有 OData 申请被 cancel,这又如何解释呢?
首先应用 Chrome 开发者工具 network 标签页里的 Initiator 性能,找到这些被 cancel 的 OData 申请,是下图第 523 行的 refresh 办法触发的:
在 refresh 办法内,如果第 600 行的标记位 bChangeDetected 为 true,那么执行第 601 行的 abortPendingRequest:
所以,这是一个“相煎何太急”的场景:在应用 SAP UI5 OData Model API 发送 OData 申请时,如果满足条件 (bChangeDetected = true),则 OData API 会终止(abort) 前一个 pending 的申请。
abortPendingRequest 的正文写道:如果开发人员能确信,以后申请的响应数据不再须要,则可调用该办法来停止该申请。回到本文结尾介绍的 Opportunity Live Search 的例子,当用户输出 J,而后再输出 e 时,显然,前一个依据 J 进行搜寻的申请,曾经不再须要了,咱们仅仅须要将 Je 对应的申请发送到后盾即可。这就是 abortPendingRequest 办法调用的应用场景之一。
总共有多少种状况,会触发 SAP UI5 去调用 abortPendingRequest 办法?
依据关键字 abortPendingRequest 搜寻,失去下列三处地位,即 OData Model 的三个 API 办法:
filter
sort
refresh
Jerry 之前 SAP CRM 开发团队的共事 Ben(文章 SAP 成都研究院李三郎:SCP Application Router 简介 的作者),对这三个 API 做了进一步的钻研。
在 SAP UI5 的 OData 框架的 ODataModel.js 中,保护了一个 HTTP 申请的 pending 列表,其内保护了曾经发送,然而还没有收到响应的 request 对象:
SAP UI5 每次发动 OData 申请时,都会调用 ODataModel 的_request()办法。该办法会把以后的 request 对象加到 pending 列表中,并通过一个 wrap method 包装回调函数,确保在响应返回时,首先把缓存的 request 对象从 pending 列表中拿掉:
每次应用 OData Model API 发动 filter, sort 和 refresh 操作时,SAP UI5 都会查看 pending 列表中是否存在 pending 的 request 对象。若存在,则先 abort 掉它,这就是咱们在 Chrome 开发者工具里察看到的状态为 canceled 的 HTTP 申请。
总结
只有同时满足下列三个条件,咱们能力察看到 SAP UI5 收回的 OData 申请被 cancel 的状况。
(1) 同一个 OData Model 实例收回的间断申请,因为 pending 列表是保护在 this 级别上的。
(2) 某个申请发送时,存在前一个状态还处于 pending 的 HTTP 申请。
(3) SAP UI5 应用程序通过 OData Model API 发动 filter, sort 或者 refresh 操作。
这也印证了本文开始 Jerry 在 for 循环里,间断调用 OData Model 的 read API 发送申请时,没有察看到呈现 cancel 的状况,因为不满足上述条件 3.
当然,大前端倒退到明天,曾经有各种欠缺的理念和计划来防止此类问题。比方函数节流 (throttle) 和防抖 (debounce) 理念:
假如咱们把用户在 Account 字段的每一次输出事件,触发的事件处理函数的执行,用一根竖线示意。则未经任何解决的原始场景,用函数节流和函数防抖从新实现的场景,三者比拟的示意图如下:
从图中不难看出,利用了函数节流和防抖机制后,事件响应函数的触发频次大大降低。当事件响应函数自身蕴含了简单耗时的业务逻辑时,触发频次的升高意味着防止了大量不必要的执行开销。
Jerry 后续的文章,会通过理论例子,来介绍 SAP UI5 如何实现函数节流和防抖,二者的区别,以及如何在 Angular 里用 RxJS 更优雅地实现这两种机制。感激浏览。
更多浏览
(0) SAP UI5 利用开发人员理解 UI5 框架代码的意义
(1) SAP UI5 module 懒加载机制
(2) SAP UI5 控件渲染机制
(3) HTML 原生事件 VS SAP UI5 Semantic 事件
(4) SAP UI5 控件元数据的元数据实现
(5) SAP UI5 控件的实例数据批改和读取逻辑
(6) SAP UI5 控件数据绑定的实现原理
(7) SAP UI5 控件数据绑定的三种模式:One Way, Two Way 和 OneTime 实现原理比拟
(8) SAP UI5 控件 ID 的生成逻辑
(9) SAP UI5 控件的多语言 (国际化,Internationalization,i18n) 反对的实现原理
(10) XML 视图里的 button 控件
(11) button 控件和它背地的 DOM 元素
更多 Jerry 的原创文章,尽在:” 汪子熙 ”: