SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗

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

本文Jerry原本写于2016年5月,当时发布于团队内部wiki.

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第1张图片

五年过后,Jerry使用的开发框架,从SAP UI5变成了Angular.

最近Jerry在做SAP Spartacus开发时,遇到了和本文描述极为类似的场景。因为我学习新知识的时候,总喜欢把之前已经熟悉的知识拿来做横向类比,所以本文首先重温一个不少SAP UI5开发人员都理解得似是而非的知识点,为后续的分享做一个铺垫。

本公众号后续的文章,会介绍如何在Angular技术栈里,使用RxJS优雅地解决此类问题。

RxJS是Jerry之前的文章 Jerry在2020 SAP全球技术大会的分享:SAP Spartacus技术介绍的文字版 曾经提到的,一个Angular重度依赖的基于Observables的响应式编程库。

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第2张图片

本文余下的部分,我们重新回到SAP UI5的世界。

My Opportunities是SAP成都研究院CRM Fiori开发团队于2014年到2016年之间,负责的CRM Fiori应用之一。用户在创建Opportunity时,需要指定Account字段,该字段支持Live Search功能,比如敲入一个字符"J", UI5会发送一个OData请求到后台,后者异步返回Account模型里fullname字段包含J的那些数据,作为搜索结果,通过下拉列表的方式显示在UI上:

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第3张图片

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

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第4张图片

当时组内有同事观察到一个现象:如果用户快速输入一连串字符,则在Chrome开发者工具Network标签页里,从时间顺序上来说,先触发的OData请求,状态会被标注为canceled:

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第5张图片

基于这个观察结果,有同事做出了这样的猜测:

极短时间内发送两个OData请求,则第一个会自动被cancel掉。

这个猜测即便纯粹从字面意义上讲,也有两点值得推敲之处:

(1) “极短时间”,多短算极短?1毫秒?1微秒?

(2) OData请求被谁cancel掉?UI5框架还是浏览器?

为了验证这个猜测是否正确,我写了一段简单的测试代码:在一个for循环里使用SAP UI5 OData Model read API,发出10个OData请求:

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第6张图片

测试发现,无论是同步还是异步请求,都未出现被cancel的情况。

10个同步请求的执行情况如下图所示:同Timeline序列栏可以看到,10个同步请求按时间顺序,被后台处理,再依次收到响应。

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第7张图片

10个异步请求的执行情况:10个请求几乎同时发出,同时收到响应。

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第8张图片

测试结果表明,这个猜测“极短时间内发送两个OData请求,则第一个会自动被cancel掉”不成立。

但是我们在Chrome开发者工具里,确实观察到有OData请求被cancel,这又如何解释呢?

首先使用Chrome开发者工具network标签页里的Initiator功能,找到这些被cancel的OData请求,是下图第523行的refresh方法触发的:

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第9张图片

在refresh方法内,如果第600行的标志位bChangeDetected为true,那么执行第601行的abortPendingRequest:

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第10张图片

所以,这是一个“相煎何太急”的场景:在使用SAP UI5 OData Model API发送OData请求时,如果满足条件(bChangeDetected = true),则OData API会终止(abort)前一个pending的请求。

abortPendingRequest的注释写道:如果开发人员能确信,当前请求的响应数据不再需要,则可调用该方法来中止该请求。回到本文开头介绍的Opportunity Live Search的例子,当用户输入J,然后再输入e时,显然,前一个根据J进行搜索的请求,已经不再需要了,我们仅仅需要将Je对应的请求发送到后台即可。这就是abortPendingRequest方法调用的使用场景之一。

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第11张图片

总共有多少种情况,会触发SAP UI5去调用abortPendingRequest方法?

根据关键字abortPendingRequest搜索,得到下列三处位置,即OData Model的三个API方法:

filter
sort
refresh

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第12张图片

Jerry之前SAP CRM开发团队的同事Ben(文章 SAP成都研究院李三郎:SCP Application Router简介 的作者),对这三个API做了进一步的研究。

在SAP UI5的OData框架的ODataModel.js中,维护了一个HTTP请求的pending列表,其内维护了已经发送,但是还没有收到响应的request对象:

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第13张图片

SAP UI5每次发起OData请求时,都会调用ODataModel的_request()方法。该方法会把当前的request对象加到pending列表中,并通过一个wrap method包装回调函数,确保在响应返回时,首先把缓存的request对象从pending列表中拿掉:

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第14张图片

每次使用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.

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第15张图片

当然,大前端发展到今天,已经有各种完善的理念和方案来避免此类问题。比如函数节流(throttle)和防抖(debounce)理念:

假设我们把用户在Account字段的每一次输入事件,触发的事件处理函数的执行,用一根竖线表示。则未经任何处理的原始场景,用函数节流和函数防抖重新实现的场景,三者比较的示意图如下:

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第16张图片

从图中不难看出,应用了函数节流和防抖机制后,事件响应函数的触发频次大大降低。当事件响应函数本身包含了复杂耗时的业务逻辑时,触发频次的降低意味着避免了大量不必要的执行开销。

Jerry后续的文章,会通过实际例子,来介绍SAP UI5如何实现函数节流和防抖,二者的区别,以及如何在Angular里用RxJS更优雅地实现这两种机制。感谢阅读。

SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗_第17张图片

更多阅读

(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的原创文章,尽在:"汪子熙":

你可能感兴趣的:(SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗)