SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗
這是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?KaTeX parse error: Expected 'EOF', got '&' at position 7: top=10&?filter=substringof(%27J%27,fullName)&sap-client=001&KaTeX parse error: Expected 'EOF', got '&' at position 19: …and=MainAddress&?select=accountID,MainAddress/city,MainAddress/country,fullName
以此類推,如果在字符J后面再敲一個e,會觸發一個新的OData請求,根據"Je"搜索:
/sap/opu/odata/sap/CRM_OPPORTUNITY/AccountCollection?KaTeX parse error: Expected 'EOF', got '&' at position 7: top=10&?filter=substringof(%27Je%27,fullName)&sap-client=001&KaTeX parse error: Expected 'EOF', got '&' at position 19: …and=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的原創文章,盡在:“汪子熙”:
總結
以上是生活随笔為你收集整理的SAP UI5 OData谣言粉碎机:极短时间内发送两个Odata request,前一个会自动被cancel掉吗的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 升学宴四字祝福语
- 下一篇: 如何查找历史版本的SAP UI5 API