SAPUI5 apps are basically JavaScript files sent to a client by a server and interpreted by the browser. So it's not only the coding of the app that can cause slow performance. It often turns out, for example, that the configuration is wrong. Slow networks or servers may also have a heavy impact on the performance of a web app. Let's have a look at the most common issues that impact performance.
Configuration issues are often caused by an old bootstrap or a wrong usage of the activated features. Here's an example of what a bootstrap should look like for an up-to-date SAPUI5 app:
<script
id="sap-ui-bootstrap"
src="/resources/sap-ui-core.js"
data-sap-ui-theme="sap_belize"
data-sap-ui-compatVersion="edge"
data-sap-ui-async="true"
data-sap-ui-onInit="module:my/app/main"
data-sap-ui-resourceroots='{"my.app": "./"}'
>
The most important setting is data-sap-ui-async="true"
. It enables
the runtime to load all the modules and preload files for declared libraries
asynchronously, if an asynchronous API is used. Setting async=true
leverages the browser's capabilities to execute multiple requests in parallel,
without blocking the UI.
The attribute data-sap-ui-onInit
defines the module
my.app.Main
, which will be loaded initially.
Configuration of the bootstrap can only be done for standalone applications and when the bootstrap is under control of the developer. The bootstrap of applications from a Fiori Launchpad is managed by the Launchpad.
The data-sap-ui-async="true"
configuration option requires
extensive testing as well as cooperation on the application side to ensure a stable
and fully working application. It is, therefore, not activated
automatically, but needs to be configured accordingly. If you encounter issues or
want to prepare your application for asynchronous loading, see Is Your Application Ready for Asynchronous Loading? The bootstrap attribute
data-sap-ui-async="true"
affects both modules
and preload files. If it is not possible to load the
modules asynchronously (e.g. for compatibility reasons), use
data-sap-ui-preload="async"
to configure at least the preloads
for asynchronous loading. For further information, see Standard Variant for Bootstrapping.
If you listen to the init
event as part of your
index.html
page, make sure that you implement the asynchronous
behavior also here, as shown in the following code snippet:
<script> sap.ui.getCore().attachInit(function() { sap.ui.require(["sap/ui/core/ComponentContainer"], function(ComponentContainer) { new ComponentContainer({ name: "your.component", manifest: true, height: "100%", componentCreated: function(oParams) { var oComponent = oParams.getParameter("component"); // do something with the component instance } }).placeAt("content"); }); }); </script>
Please note that this variant with inline scripting is not CSP-compliant. It is
better to create a module with sap.ui.define
which contains the
startup code and load it via
data-sap-ui-onInit="module:my/app/main"
( this usually also
requires a declaration of data-sap-ui-resourceroots
, e.g.:
data-sap-ui-resourceroots='{"my.app": "./"}
).
Applications without a descriptor file can declare additional dependencies
explicitly via the bootstrap parameter data-sap-ui-libs
. If those
dependencies are not listed, such as transitive dependencies that are inherited from
a listed library, SAPUI5 will load them automatically, but then has to first read the configured libraries
and find out about these dependencies. This can take time as the application might
benefit less from parallel loading.
Additional Information:
Please check the rootView
of the application's
manifest.json
file for an async=true
parameter. This allows the root view to be loaded asynchronously.
To configure the targets for asynchronous loading, please also check the Routing Configuration for the
async=true
parameter.
"sap.ui5": { "rootView": { "viewName": "sap.ui.demo.walkthrough.view.App", "type": "XML", "id": "app", "async": true }, "routing": { "config": { "routerClass": "sap.m.routing.Router", "viewType": "XML", "viewPath": "sap.ui.demo.walkthrough.view", "controlId": "app", "controlAggregation": "pages", "async": true } }, ...
Additional Information:
If modules follow the Asynchronous Module Definition (AMD) standard and the bootstrap
flag data-sap-ui-async
is set to true
, custom
scripts and other modules can also be loaded asynchronously when a preload is not
available. It will help you in the future to enable asynchronous loading of
individual modules combined with the usage of HTTP/2 or AMD-based module bundlers.
It also ensures proper dependency tracking between modules.
But it isn't enough to write AMD modules. You also need to prevent access to SAPUI5 classes via
global names. For instance, do not use global namespaces like new
sap.m.Button()
but require the Button
and call its
constructor via the local AMD reference instead.
sap.ui.define
.
Always avoid usages of sap.ui.requireSync
and
jQuery.sap.require
! In order to enable modules to load
asynchronously, use sap.ui.define
to create modules (e.g.
controllers or components) or sap.ui.require
in other cases.
Please follow the Best Practices for Loading Modules.
manifest.json
Instead of the Bootstrap to Define
DependenciesDon't specify a link to the CSS in the bootstrap of your app; use the
manifest.json
descriptor file instead.
Please use the manifest.json
application descriptor file to declare
dependencies. This has several advantages:
Make sure that you don't load too many dependencies. In most apps it's enough to load
the libraries sap.ui.core
and sap.m
by default,
and add additional libraries only when needed.
If you want to make additional libraries generally known in your app, without
directly loading them during the app start, you can add them to the dependency
declaration in the manifest.json
file with the
lazy
loading option. This makes sure that the libraries are
only loaded when they are
needed:
"sap.ui5": {
"dependencies": {
"minUI5Version": "1.70.0",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.ui.layout": {
"lazy": true
}
},
...
If a library preload contains reuse components and this preload is configured to be
loaded lazily (via "lazy": true
in the dependencies of the
manifest.json
), the library is not available upon creation of
the related component.
In this case you need to use
sap.ui.getCore().loadLibrary("my.library")
before creating the
component (e.g with Component.create({ name: "my.component" })
or
component usage myComponent.createComponent("myUsage")
).
An indicator that a component is inside a library is the existence of an entry
sap.app/embeddedBy
in its manifest.json
file.
Additional Information:
In order to ensure that all static SAPUI5 resources are served with the lowest possible latency in SAP Cloud Platform scenarios, you can load the resources from the Content Delivery Network (CDN) cached by AKAMAI. Especially when running your app in the cloud, you benefit from the global distribution of servers. For other scenarios, it is possible to configure a custom CDN of choice as an external location.
Additional Information:
Languages can be configured in your manifest since UI5 version 1.77.
The manifest configuration for i18n has now the option to provide the
supportedLocales
and the fallbackLocale
:
supportedLocales
should contain all languages for which
you have i18n files. e.g. a file named i18n_en.properties
has the locale en
.fallbackLocale
is the locale loaded before falling back
to the root bundle.Example: If the following language files exist:
i18n_en.properties
(English version,
"en"
)i18n_de.properties
(German version,
"de"
)they can be configured in your manifest.json
in Section
sap.ui5
under models
:
"sap.ui5": { "models": { "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { "bundleName": "sap.ui.demo.todo.i18n.i18n", "supportedLocales": ["en", "de"], "fallbackLocale": "en" } } } }
With AppDescriptor version 1.21.0 this is also possible in the i18n
section of sap.app
in your manifest.json
:
"sap.app": { "i18n": { "bundleUrl": "i18n/i18n.properties", "supportedLocales": ["en", "de"], "fallbackLocale": "en" } }
For more informations, see:
Load the manifest.json
descriptor file of the component first to
analyze and preload the dependencies when loading the component. For more
information, see Manifest First Function.
// "Component" required from module "sap/ui/core/Component" // load manifest.json from default location and evaluate it before creating an instance of the component Component.create({ name: "my.component", });
If the library preloads are disabled or not found, every module is loaded separately by an own request. Depending on the server and network infrastructure, this can take a lot of time. Except for debugging reasons, it is always recommended to make sure library preloads are used. Fortunately, the library preloads are active by default if the files are present.
In some cases it may happen that preloads are disabled:
The data-sap-ui-preload
bootstrap attribute is empty or set
to an invalid value. The attribute is optional and only necessary if the
loading behavior (sync / async) needs to be overwritten manually.
data-sap-ui-debug=true
) or via the URL
(sap-ui-debug=true
).Application modules (e.g. components, controllers, views or resource bundles) should
be loaded asynchronously via the component preload file. Check (e.g. via the Network
tab in the Google Chrome developer tools) if a component preload
(Component-preload.js
) is missing. If the application is not
configured to load modules asynchronously, required application files may be loaded
synchronously.
If a component preload does not exist yet, the bundle needs to be created. For example, you may use the UI5 Tooling.
To quickly check the network load caused by your app, look at your browser's developer tools, for example the Network tab in the Google Chrome developer tools (F12). You'll see an overview of all requests being sent. Possible issues here may be:
In this case, use the data-sap-ui-async="true"
setting in the
bootstrap.
You can use the UI5 Tooling to bundle and minimize all relevant component files by creating a component-preload file.
If you're using apps with grunt as a web server, you
can use the openui5_preload
task; for more information see
Optimizing OpenUI5/SAPUI5 Apps in the
SAPUI5 Developer Center on SAP SCN.
If you're using SAP Web IDE, refer to Application Build in the SAP Web IDE documentation.
Slow database service (e.g. OData)
Additional Information:
jquery.sap.*
Modules to their Modularised
VariantsSince UI5 version 1.58, the global jquery.sap.*
modules are
deprecated. Please use the modularised variant of the module. If you are still using
the jquery.sap.*
variants, a so-called "stubbing layer" may load
the old module synchronously!
You can find a list of modules in the Legacy jQuery.sap Replacement documentation.
The usages can either be replaced manually or by the UI5 Migration Tool.
Please make sure to declare the required modules in
sap.ui.define
or sap.ui.require
to ensure
that they get loaded asynchronously.
Check if the application uses synchronous UI5 factories. Many asynchronous variants are available, e.g. for Components, Resource Bundles, Controllers, Views and Fragments. Please visit the following overview:Legacy Factories Replacement.
Components can preload models for which modules are already loaded; otherwise a warning will be shown. The OData model (V2 or V4) benefits especially, because the metadata can be loaded in parallel during a component load.
"sap.ui5": { ... "models": { "mymodel": { "preload": true, ...
For the OData V2 model, also consider using the model parameter
earlyTokenRequest
. For more
information, see the API Reference:
sap.ui.model.odata.v2.ODataModel
.
For the OData V4 model, also consider using the model parameter
earlyRequests
. For more
information, see the API Reference:
sap.ui.model.odata.v4.ODataModel
.
For more information, see Manifest Model Preload.
To ensure fast loading times for SAP Fiori applications started from the
SAP Fiori launchpad, the OData metadata is cached on the web browser
using cache tokens. The tokens are added with the parameter
sap-context-token
to the URL of metadata requests. Please check
via the developer tools of your browser (e.g. the Network tab in the Google Chrome
developer tools) if the token has been appended to the request URL.
This feature is currently only supported for ABAP back ends.
Additional Information:
The performance limits are reached differently depending on the used browser,
operating system and hardware. Therefore, it is important to be mindful about the
amount of controls and data bindings. This applies especially to lists and their
variants (e.g. sap.m.Table
or
sap.ui.table.Table
):
sap.ui.table.Table
instead of
sap.m.Table
The reason for this is that
sap.m.Table
keeps every loaded row in memory, even if
not visible after scrolling. To choose the right table variant for your
requirements, check out the documentation about Tables: Which One Should I Choose?Additional Information:
You can further optimize your code by doing the following:
Use asynchronous view loading as described here: Instantiating Views.
Use the OData V4 model, which has an improved performance over the OData V2 model.
Visit the OData V4 Model documentation and ensure that all required features are available.
For a quick start, follow the OData V4 tutorial.
If you use data binding with an OData V2 service as a back end, you should consider switching your OData model to our more updated OData V2 model. For more information, see OData V2 Model.
Optimize dependent bindings as described here: Optimizing Dependent Bindings.
Avoid the usage of setTimeout()
calls with values
greater than 0
. This usually indicates an anti-pattern
in application code that is used as a workaround and should be avoided.
For more information, see also JavaScript Code
Issues: Don't use timeouts.
Don't use visibility for lazy instantiation. For more information, see Performance Issues: Don't use visibility for lazy instantiation.
XML Preprocessor
is used, we recommend to use the
XML View Cache. If configured in
the XML View and with a properly implemented key provider (for
invalidation), it is able to cache already processed XML View Preprocessor
results.