有时咱们能在Chrome开发者工具的Network tab里观察到SAP UI5应用会发出某些状态为"取消"的OData请求。以下图第五个请求。浏览器
以前有一种似是而非的说法:极短期内发送两个OData请求,则第一个会自动被cancel掉。缓存
这个说法从字面上看,有两点值得推敲:框架
1. cancel掉,被谁cancel掉?UI5框架仍是Chrome?异步
2. “极短”,多短算极短?函数
我用代码在for循环里一共发10个OData请求:工具
不管是同步仍是异步,都没有任何的请求被cancel。this
10个同步请求:spa
10个异步请求:代理
就算发100个request都不会有一个request被cancel:对象
验证结果,以前的说法“极短期内发送两个OData request,前一个会自动被cancel掉”是错误的。
那再回到本文第一张图观察到的cancel的场景, 缘由到底是什么?
观察产生了被取消的OData请求的应用代码,观察到第523行有这个refresh操做:
在这个方法的第601行,bChangeDetected变量为true致使abortPendingRequest的调用。
abortPendingRequest的注释已经很清楚地说明问题了。
什么状况下会致使AbortPendingRequest? 直接使用Chrome开发者工具的全文搜索获得答案:OData model的三个API: filter, sort, refresh
下面是个人同事Li Ben的进一步补充。
1. 在哪里能够看到这个cancel现象?
在咱们的live search功能上,若是输入较快或者正常速度输入,会看到前面不少输入请求都会被cancel掉:
若是输入较慢则不会:
真的是快慢的缘由吗?
仔细观察network发现,真正的缘由是当上一次的network还处于pending状态的时候,继续输入发起的请求就会cancel掉上一次的请求:
继续深究, 这是在哪里作到的?
在SAP UI5的OData框架里面有这样的实现:
在ODataModel.js中维护了一个http request的pending list,将已经发送可是尚未收到响应的request对象都缓存在这个列表中:
每次发起OData请求的时候都会调用ODataModel的_request()方法,这个方法会把当前的request加到pending list中,而且经过一个wrap method包装回调函数,确保在响应返回的时候首先把缓存的request对象从pending list中拿掉:
每次在OData Model上发起filter, sort, refresh操做的时候,都会检查是否存在pending的request对象,若是存在未完成的请求,abort掉它:
回答上面的问题,在什么状况下会发生这种现象?
1. 同一个ODataModel的instance上发出的连续请求,由于pending list是缓存在this级别上面的。
2. 前一个Http请求的network还处于pending status的时候。
3. 就读ODataModel的代码和观察到的现象,在ODataModel上发起filter, sort或者refresh的时候。
为何在OData的request对象上发起abort调用就能够取消底层的network call?
简单的说,UI5里面的OData Request对象是底层的Ajax Request对象XmlHttpRequest的一个代理,在ODataModel的_submit方法中:
具体实现是UI5中利用了一个第三方的库datajs,datajs最终会调用浏览器的底层http对象XMLHttpRequest: