SAP UI5 謠言粉碎機:極短時間內傳送兩個Odata請求,前一個會自動被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?$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框架程式碼的意義
(2) SAP UI5 控制元件渲染機制
(3) HTML原生事件 VS SAP UI5 Semantic事件
(7) SAP UI5控制元件資料繫結的三種模式:One Way, Two Way和OneTime實現原理比較
(8) SAP UI5控制元件ID的生成邏輯
(9) SAP UI5控制元件的多語言(國際化,Internationalization,i18n)支援的實現原理
(10) XML檢視裡的button控制元件
(11) button控制元件和它背後的DOM元素
更多Jerry的原創文章,盡在:"汪子熙":
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24475491/viewspace-2754415/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 謠言粉碎機-極短時間內傳送兩個Odatarequest,前一個會自動被cancel掉?
- SAP UI5 應用的 OData 後設資料請求的傳送原理分析UI
- CORS跨域時,為何會傳送兩次請求?CORS跨域
- 什麼時候會傳送options請求
- 『動善時』JMeter基礎 — 6、使用JMeter傳送一個最基礎的請求JMeter
- 如何使用jMeter傳送兩個邏輯上相關的HTTP請求JMeterHTTP
- 我是一個請求,我是如何被髮送的?
- SAP UI5 Mock Server 在響應 OData 請求時的單步除錯UIMockServer除錯
- SAP UI5 OData 請求的自定義 HTTP header 設定方法UIHTTPHeader
- python+pytest介面自動化傳送post請求Python
- python+resuests 傳送請求,結果中如果欄位的值是 null 就會被 json 自動過濾掉,請問如何才能不被過濾PythonNullJSON
- 如何使用 Postman 傳送 SAP OData Batch 請求到 ABAP 後臺伺服器試讀版PostmanBAT伺服器
- 使用 Busy Dialog 動畫阻止 SAP UI5 應用按鈕短時間內快速被點選試讀版動畫UI
- Go HTTP GET 請求可以傳送 body 嗎GoHTTP
- 【python介面自動化】- 使用requests庫傳送http請求PythonHTTP
- js網路請求 短時間發出多個 展示最新響應JS
- Tips_傳送請求時新增一個隨機數引數,讓瀏覽器每次都重新發請求到伺服器隨機瀏覽器伺服器
- python+pytest介面自動化(4)-requests傳送get請求Python
- axios傳送兩次請求原因及解決方法iOS
- 『動善時』JMeter基礎 — 14、使用JMeter傳送Post請求JMeter
- java傳送http請求JavaHTTP
- Postman傳送Post請求Postman
- 傳送GET請求 示例
- Java傳送Post請求Java
- Element頁面內多個上傳元件 超時使用abort取消請求元件
- 利用post請求傳送內容進行爬蟲爬蟲
- SpringMVC中如何傳送GET請求、POST請求、PUT請求、DELETE請求。SpringMVCdelete
- SAP UI5 應用的 OData 後設資料請求響應的解析原理分析UI
- 使用Feign傳送HTTP請求HTTP
- 如何傳送請求以及AJAX
- python傳送HTTP POST請求PythonHTTP
- 傳送請求時,url 出現亂碼錯誤
- 傳送新請求,取消上一次pending狀態的同一請求
- 如何透過 SAP ABAP OData $expand 操作在同一個 HTTP 請求中返回多個節點的資料試讀版HTTP
- postman和SAP UI5應用傳送同樣的HTTP請求,為何前者成功,後者失敗?PostmanUIHTTP
- 在瀏覽器輸入一個地址, 傳送請求, 經歷了哪些過程?瀏覽器
- Postman傳送請求引數是Map格式的請求Postman
- Vue 使用 Axios 傳送請求的請求體問題VueiOS