15 KiB
SAPUI5 Performance Optimization
Source: Official SAP SAPUI5 Documentation Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps Last Updated: 2025-11-21
Core Loading Strategies
1. Asynchronous Loading (Critical)
Always enable asynchronous loading for optimal performance.
Bootstrap Configuration:
<script
id="sap-ui-bootstrap"
src="resources/sap-ui-core.js"
data-sap-ui-async="true"
data-sap-ui-on-init="module:sap/ui/core/ComponentSupport"
data-sap-ui-resource-roots='{
"my.app": "./"
}'>
</script>
Component Interface:
sap.ui.define([
"sap/ui/core/UIComponent"
], function(UIComponent) {
"use strict";
return UIComponent.extend("my.app.Component", {
interfaces: ["sap.ui.core.IAsyncContentCreation"],
metadata: {
manifest: "json"
}
});
});
Benefits:
- Non-blocking module loading
- Parallel resource fetching
- Faster initial load time
- Better user experience
2. Manifest-First Approach
Configure dependencies in manifest.json instead of bootstrap.
manifest.json:
{
"sap.ui5": {
"dependencies": {
"minUI5Version": "1.120.0",
"libs": {
"sap.m": {},
"sap.ui.core": {},
"sap.f": {}
}
}
}
}
Benefits:
- Dependency reuse across contexts
- Earlier rendering
- Parallel loading optimization
- Design-time tool support
3. Lazy Loading Libraries
Load heavy libraries only when needed:
manifest.json:
{
"sap.ui5": {
"dependencies": {
"libs": {
"sap.m": {},
"sap.ui.table": {
"lazy": true
}
}
}
}
}
Load Before Use:
sap.ui.require(["sap/ui/core/Lib"], function(Library) {
Library.load({ name: "sap.ui.table" }).then(function() {
// Library loaded, now create table
});
});
Resource Optimization
1. CDN Distribution
Load SAPUI5 from CDN for better performance:
<script
src="[https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"](https://sapui5.hana.ondemand.com/resources/sap-ui-core.js")
data-sap-ui-async="true">
</script>
Benefits:
- Global CDN distribution (AKAMAI)
- Reduced latency
- Caching across applications
- No server load
2. Component Preload
Enable component preload to bundle resources:
Automatic (UI5 Tooling):
ui5 build
Creates Component-preload.js containing:
- All views
- All controllers
- All fragments
- manifest.json
- i18n files
Load Component Preload:
{
"sap.ui5": {
"dependencies": {
"components": {
"my.other.component": {
"lazy": false // Preload enabled by default
}
}
}
}
}
3. Library Preloads
Ensure library preloads are enabled (default):
Check Configuration:
// Preloads enabled by default
// Don't set data-sap-ui-preload="sync" (synchronous loading)
Verify Preload Loading:
- Open Network tab in browser
- Look for
library-preload.jsfiles - Should see ONE request per library, not many
4. i18n Configuration
Prevent 404 errors for missing language files:
manifest.json:
{
"sap.ui5": {
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "my.app.i18n.i18n",
"supportedLocales": ["en", "de", "fr"],
"fallbackLocale": "en"
}
}
}
}
}
File Structure:
i18n/
├── i18n.properties (fallback)
├── i18n_en.properties (English)
├── i18n_de.properties (German)
└── i18n_fr.properties (French)
Code Optimization
1. Replace Deprecated jQuery
Migrate from deprecated jquery.sap.* modules:
Before (deprecated):
jQuery.sap.require("sap.m.MessageBox");
jQuery.sap.delayedCall(100, this, function() {});
After (modern):
sap.ui.require(["sap/m/MessageBox"], function(MessageBox) {});
setTimeout(function() {}, 100);
Migration Guide:
jQuery.sap.delayedCall→setTimeoutjQuery.sap.log→sap/base/LogjQuery.sap.uid→sap/base/util/uidjQuery.sap.getUriParameters→sap/base/util/UriParameters
2. Asynchronous Factories
Use async variants for better performance:
Components:
// Old (sync)
var oComponent = sap.ui.component({
name: "my.app"
});
// New (async)
sap.ui.require(["sap/ui/core/Component"], function(Component) {
Component.create({
name: "my.app",
manifest: true
}).then(function(oComponent) {
// Component ready
});
});
Views:
// Old (sync)
var oView = sap.ui.view({
viewName: "my.app.view.Main",
type: "XML"
});
// New (async)
sap.ui.require(["sap/ui/core/mvc/XMLView"], function(XMLView) {
XMLView.create({
viewName: "my.app.view.Main"
}).then(function(oView) {
// View ready
});
});
Controllers:
// Controllers loaded automatically with views (async)
Resource Bundles:
// Old (sync)
var oBundle = jQuery.sap.resources({
url: "i18n/i18n.properties"
});
// New (async)
sap.ui.require(["sap/base/i18n/ResourceBundle"], function(ResourceBundle) {
ResourceBundle.create({
url: "i18n/i18n.properties",
async: true
}).then(function(oBundle) {
// Bundle ready
});
});
Data Handling
1. OData Model Preload
Enable metadata preloading:
manifest.json:
{
"sap.ui5": {
"models": {
"": {
"dataSource": "mainService",
"preload": true,
"settings": {
"defaultBindingMode": "TwoWay"
}
}
}
}
}
Benefits:
- Metadata loads during component init
- Faster first data request
- No metadata loading delay
2. Use $select for OData
Fetch only needed properties:
Without $select (bad):
// Fetches ALL properties
this.getView().bindElement("/Products('123')");
With $select (good):
// Fetches only specified properties
this.getView().bindElement({
path: "/Products('123')",
parameters: {
select: "ProductID,Name,Price,Category"
}
});
In List/Table:
<Table
items="{
path: '/Products',
parameters: {
select: 'ProductID,Name,Price',
expand: 'Category'
}
}">
Benefits:
- Smaller payload
- Faster backend queries
- Reduced network transfer
- Better performance
3. OData V4 Migration
Prefer OData V4 over V2:
manifest.json:
{
"sap.app": {
"dataSources": {
"mainService": {
"uri": "/odata/v4/catalog/",
"type": "OData",
"settings": {
"odataVersion": "4.0"
}
}
}
},
"sap.ui5": {
"models": {
"": {
"dataSource": "mainService",
"settings": {
"synchronizationMode": "None",
"operationMode": "Server",
"autoExpandSelect": true
}
}
}
}
}
Benefits:
- Better performance
- Server-side operations
- Automatic $expand and $select
- Modern features
4. Batch Requests
Combine multiple requests:
OData V2:
var oModel = this.getView().getModel();
oModel.setUseBatch(true);
oModel.setDeferredGroups(["changes"]);
// Add to batch
oModel.create("/Products", oData1, { groupId: "changes" });
oModel.create("/Products", oData2, { groupId: "changes" });
oModel.update("/Products('1')", oData3, { groupId: "changes" });
// Submit batch
oModel.submitChanges({
groupId: "changes",
success: function() {
MessageToast.show("All changes saved");
}
});
Benefits:
- Single HTTP request
- Reduced network overhead
- Better performance
- Atomic operations
5. Metadata Caching
Enable metadata caching for ABAP backends:
Automatic: SAPUI5 uses cache tokens automatically
Check Network:
- Look for
sap-context-tokenparameter - Metadata should load from cache on subsequent visits
UI Control Performance
1. Table Selection
Choose appropriate table control:
sap.m.Table (Mobile/Responsive):
- Good for: < 100 rows
- Keeps all rows in DOM
- Better for responsive layouts
- Growing/scrolling support
sap.ui.table.Table (Grid/Analytical):
- Good for: 100+ rows
- Virtual scrolling (only visible rows in DOM)
- High performance for large datasets
- Fixed column layout
Example:
<!-- For < 100 rows -->
<m:Table
items="{/Products}"
growing="true"
growingThreshold="20">
</m:Table>
<!-- For 100+ rows -->
<table:Table
rows="{/Products}"
visibleRowCount="20"
threshold="50">
</table:Table>
2. Reduce Control Complexity
Minimize controls in repeated aggregations:
Bad (heavy):
<items>
<ColumnListItem>
<cells>
<VBox>
<Text text="{Name}"/>
<Text text="{Description}"/>
<HBox>
<Button text="Edit"/>
<Button text="Delete"/>
</HBox>
</VBox>
</cells>
</ColumnListItem>
</items>
Good (light):
<items>
<ColumnListItem>
<cells>
<ObjectIdentifier
title="{Name}"
text="{Description}"/>
</cells>
</ColumnListItem>
</items>
3. Remove Hidden Columns
Don't hide columns with visible="false" in tables - remove them entirely:
Bad:
<columns>
<Column visible="false">
<Text text="Hidden Column"/>
</Column>
</columns>
Good:
// Add/remove columns dynamically based on device
if (sap.ui.Device.system.desktop) {
oTable.addColumn(oColumn);
}
Network & Debugging
1. Network Inspection
Monitor browser Network tab:
Check for:
- Synchronous blocking requests (waterfall shows blocks)
- Excessive request count (> 50 for initial load)
- Large response sizes
- Slow backend responses
- 404 errors (missing files)
- Duplicate requests
Tools:
- Chrome DevTools Network tab
- Firefox Network Monitor
- UI5 Inspector extension
2. Avoid Debug Mode
Never use debug mode in production:
Development:
[http://localhost:8080/index.html?sap-ui-debug=true](http://localhost:8080/index.html?sap-ui-debug=true)
Production (don't do this):
[http://myapp.com/index.html?sap-ui-debug=true](http://myapp.com/index.html?sap-ui-debug=true)
Why: Debug mode loads individual source files instead of preloads.
3. Performance Measurement
Use built-in performance tools:
Enable Performance Trace:
sap.ui.require(["sap/ui/performance/Measurement"], function(Measurement) {
Measurement.setActive(true);
// Custom measurements
Measurement.start("myOperation");
// ... operation ...
Measurement.end("myOperation");
// Get results
var aMeasurements = Measurement.getAllMeasurements();
console.table(aMeasurements);
});
UI5 Inspector:
- Open UI5 Inspector extension
- Go to Performance tab
- See loading times, rendering times, etc.
Anti-Patterns to Avoid
1. setTimeout with Delays
Bad:
setTimeout(function() {
this.doSomething();
}.bind(this), 100); // 100ms delay
Good:
// Do immediately when possible
this.doSomething();
// Or use events
this.attachEventOnce("dataReceived", this.doSomething, this);
2. Visibility-Based Lazy Loading
Bad:
onAfterRendering: function() {
if (this.byId("panel").getVisible()) {
this.loadData();
}
}
Good:
// Use routing or explicit user actions
onButtonPress: function() {
this.loadData();
}
3. Blocking Rendering
Bad:
onInit: function() {
// Blocks rendering until data loaded
var oData = this.loadDataSync(); // Synchronous
this.getView().setModel(new JSONModel(oData));
}
Good:
onInit: function() {
// Show loading, load async
this.getView().setBusy(true);
this.loadDataAsync().then(function(oData) {
this.getView().setModel(new JSONModel(oData));
this.getView().setBusy(false);
}.bind(this));
}
4. Excessive Dependencies
Bad:
sap.ui.define([
"sap/m/Button",
"sap/m/Input",
"sap/m/Text",
// ... 50 more controls
], function(Button, Input, Text, ...) {
// Only using 5 of them
});
Good:
sap.ui.define([
"sap/m/Button",
"sap/m/Input"
], function(Button, Input) {
// Only what's needed
});
Performance Checklist
Loading
- Async loading enabled (
data-sap-ui-async="true") - Component implements
IAsyncContentCreation - Dependencies in manifest.json
- Heavy libraries lazy loaded
- Component preload generated
- CDN used for SAPUI5
Data
- OData metadata preload enabled
- $select used for queries
- Batch requests for multiple operations
- OData V4 used when possible
- Metadata caching working
UI
- Appropriate table control chosen
- Virtual scrolling for large lists
- Control complexity minimized
- No hidden columns in tables
- Growing lists for mobile
Code
- No deprecated jQuery.sap modules
- Async factories used
- No setTimeout delays
- No visibility-based lazy loading
- No blocking rendering
Network
- < 50 requests for initial load
- No 404 errors
- No duplicate requests
- Debug mode disabled
- Preloads loading correctly
Performance Metrics
Target Initial Load Time:
- 3G Network: < 5 seconds
- LTE Network: < 2 seconds
- Desktop/WiFi: < 1 second
Measure Performance:
# Lighthouse audit
lighthouse [https://myapp.com](https://myapp.com) --view
# WebPageTest
# Visit [https://www.webpagetest.org/](https://www.webpagetest.org/)
Official Documentation
- Performance: https://github.com/SAP-docs/sapui5/tree/main/docs/05_Developing_Apps (search: performance)
- Best Practices: https://sapui5.hana.ondemand.com/#/topic/408b40efed3c416681e1bd8cdd8910d4
- Performance Measurement: https://sapui5.hana.ondemand.com/#/api/sap.ui.performance.Measurement
Note: This document covers performance optimization for SAPUI5 applications. Implement these practices for production-ready, high-performance applications.