I'm staring my UI5 with the following bootstrapping in index.js
:
sap.ui.define([
"sap/m/Shell",
"sap/ui/core/ComponentContainer"
], (Core, Shell, ComponentContainer) => {
"use strict";
new Shell("", {
app: new ComponentContainer("", {
height: "100%",
name: "webapp"
}),
appWidthLimited: false
}).placeAt("content");
});
According to the UI5 documentation:
Static dependencies are loaded in the dependency declaration array of the
sap.ui.define
call. These dependencies are always loaded in advance before executing the defined module.
Do I understand it correctly that in such case the modules will be always loaded in a synchronous way and there is no real way to avoid the «Synchronous XMLHttpRequest on the main thread» warning?
Can I, perhaps, just wrap new sap.m.Shell(sId?, mSettings?)
with async
/await
?
I've checked the loading with ?sap-ui-xx-nosync=warn
and got the following results:
For some reason i18n/i18n_en.properties
is loaded synchronously. The only place where I'm accessing the i18n
is:
const oBundle = myI18nModel.getResourceBundle();
But following the documentation, I could not grasp why myI18nModel.getResourceBundle()
leads to the synchronous loading.
After a deep exploration of no sync XHR sample, I found out the reason for the sync XHR
warning. That was "description": "{{appDescription}}"
and "title": "{{appTitle}}"
in manifest.json
which is explicitly noted:
"title": "Here the i18n bundles can't be loaded with 'async: true' yet!",
"description": "Same here. Hence, no 'i18n' in this 'sap.app' section!"
After replacing it with a static values the warning is gone.
Historically, UI5 1.x had been offering APIs based on synchronous XMLHttpRequest
(sync XHR). In order to avoid breaking existing apps and to support backward compatibility of new minor and patch releases, UI5 1.x must keep the current APIs. Legacy applications or outdated documentation topics might still refer to:
sap.ui.core.ComponentContainer
, sap.ui.component
, sap.ui.*view
, sap.ui.controller
, Core#loadLibrary
, sap.ui.model.odata.ODataModel
etc.sap.ui.*fragment
, jQuery.sap.require
, jQuery.sap.sjax
, sap.ui.requireSync
, Core#createComponent
, sap.ushell.Container.getService
, etc.In either case, the good news is that it is still possible to avoid most of the sync XHRs today.
In order to get rid of sync XHRs in UI5:
Do not use deprecated APIs such as those mentioned above which btw. will be removed in the next major UI5 version 2.x. Reports by UI5 linter, TypeScript, and the browser console at runtime (F12) can help detecting deprecated APIs in your project
Make sure that dependent libraries and components are preloaded before accessing modules from the respective preload bundle. See How to reduce sequential requests in SAPUI5? .
Let UI5 modules load asynchronously.
For apps on Fiori launchpad (FLP): enable the Asynchronous Module Loading setting and follow How to Fix "String as JavaScript" Errors in FLP? (Async Module Loading)
For standalone apps:
data-sap-ui-async="true"
is added.UIComponent
by itself, use the declarative sap/ui/core/ComponentSupport
module in sap-ui-onInit
instead of instantiating sap.ui.core.ComponentContainer
manually. The ComponentSupport automatically instantiates the ComponentContainer, loads the corresponding manifest and Component in that order asynchronously, and renders the container in the UI altogether while avoiding inline scripts to allow stricter Content Security Policy.<head>
<!-- ... -->
<script id="sap-ui-bootstrap"
src="https://ui5.sap.com/1.120/resources/sap-ui-core.js"
data-sap-ui-async="true"
data-sap-ui-onInit="module:sap/ui/core/ComponentSupport"
data-sap-ui-resourceRoots='{ "my.demo": "./" }'
data-sap-ui-modules="sap/ui/thirdparty/datajs,..."
data-sap-ui-...="..."
></script>
<!-- No inline script. No ComponentContainer. No attachInit. -->
</head>
<body id="content" class="sapUiBody">
<div data-sap-ui-component
data-id="rootComponentContainer"
data-name="my.demo"
data-settings='{ "id": "myRootComponent" }'
data-...="..."
></div>
</body>
The sap/ui/thirdparty/datajs
is required by v2.ODataModel
as the manifest models are created synchronously until UI5 1.120 (Cf. Issue #3134). Add more modules to sap-ui-modules
if needed.
For code without manifest.json
: add data-sap-ui-libs="sap.ui.core,sap.m,..."
and data-sap-ui-onInit="<onUI5Init>"
in addition to data-sap-ui-async="true"
. Regarding the "onUI5Init": What is the "onUI5Init" global event?
In the Component controller, add manifest: "json"
(if the project contains manifest.json
) and the "sap.ui.core.IAsyncContentCreation"
marker interface.
// Component.js
return UIComponent.extend("my.demo.Component", {
metadata: {
manifest: "json",
interfaces: [ "sap.ui.core.IAsyncContentCreation" ],
},
// ...
});
Let the framework fetch i18n *.properties
asynchronously by setting async
: true
.
"sap.ui5": {
"models": {
"<myI18nModel>": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"async": true,
new ResourceModel({ // sap/ui/model/resource/ResourceModel
async: true,
ResourceBundle.create({ // sap/base/i18n/ResourceBundle
async: true,
Note: This will make ResourceModel#getResourceBundle()
and ResourceBundle.create
return a Promise. Refer to the API reference and adjust your code accordingly.
Ensure that the application code really doesn't initiate any sync XHR by itself, e.g. setting async: false
in jQuery.ajax
or passing a falsy 3rd argument to XMLHttpRequest#open
.
To detect more sync XHRs initiated by UI5, run the app with the xx-nosync
* bootstrap option. For example, in the URL:
https://<host>/my/awesome/app/?sap-ui-xx-nosync=warn
* Bug: since 1.120, you might have to use xx-no-sync
instead.
UI5 will then log "loading … with sync XHR" or "[nosync] loading module '…'" in the browser console for each file fetched synchronously (Ignore other [nosync] messages).
See also other Best Practices for UI5 Developers.
There are, however, still some APIs left which have no asynchronous replacements yet such as:
sap/ui/core/LocaleData
(Used in e.g. Calendar or DatePicker)."{{...}}"
-syntax in manifest.json
resulting in sync XHRs. (Should not be an issue if the *.properties
files are included in the generated application bundle Component-preload.js
). → ✅ Fixed with ad5cf65
.v2.ODataModel
requiring datajs.js
synchronously if created with preload: true
in manifest.json
. → ✅ Fixed with 337b176
.To answer the question: sap.ui.define
and sap.ui.require
do load dependencies asynchronously if the data-sap-ui-async
config is set to true
which can replace data-sap-ui-preload="async"
. Wrapping a synchronous content request with async-await or Promise won't help. Better look for newer APIs.