Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
frederic_berg
Employee
Employee
After covering some of the basic aspects on how to improve the startup performance of SAPUI5 applications in my last post, I will cover some more advanced topics which nonetheless should apply to almost all applications.

Here's the link to the post covering the basic aspects:
https://blogs.sap.com/2016/10/29/sapui5-application-startup-performance-best-practices/

Basic Setup


We will start with a typical application which you can download right here:
https://github.com/frdrcbrg/ui5-performance-advanced


I will deploy this application to HCP in a location rather far away from where I am located to get a real impression of how latency will affect the load times of this app.

The application itself will connect to the Northwind OData Service (V2 - Read Only). More information on this service can be found right here:
http://www.odata.org/odata-services/

The data will be shown on the first page of the application directly when the app starts. This is a screenshot of the final application:



And here is the application structure.



This is a typical application structure (compare with the application which we set up in the first post: https://blogs.sap.com/2016/10/29/sapui5-application-startup-performance-best-practices/

Let's see how this application performs right now:




Note: 29 requests, Finish in about 3,5s (uncached). 

This application is already using all performance optimizations described in the post linked above and still has some room for improvement. Let's look at some common issues and fix them one by one.

1. Asynchronous Component Loading


Modern UI5 applications should attempt to completely remove synchronous processing (which is not yet completely possible, but we're working on it).

Components however can be loaded asynchronously and this is the new best practice approach. Here's the updated index.html inline script content:
	<script>
sap.ui.getCore().attachInit(function () {

var oCompContainer = new sap.ui.core.ComponentContainer({
height : "100%"
})

new sap.m.Shell({
app: oCompContainer,
showLogout:false
}).placeAt("content");

var oComponent = sap.ui.component({
name: "myapp",
manifestFirst: true,
async: true
}).then(function(oComponent){
oCompContainer.setComponent(oComponent);
});

});
</script>

Let's try to understand what is happening here.

We first create a component container (which is needed to render a component). Next, we pass the component container to our Shell control and directly start to render the Shell (using the placeAt function). This means, the Shell will become visible already very early on

Next we create our Component instance, specifying the asynchronous behaviour (async:true) and also make sure that SAPUI5 attempts to first load the manifest.json (manifestFirst:true). This is important since this file contains a list of all dependencies which can be loaded in parallel to the component preload and other files.

The Component provides a promise which will resolve eventually giving us the chance to finally connect the component container with this component instance. At this point in time, the component's inner content will be rendered.

To sum this up:

  • We now load the component asynchronously

  • We also load all relevant dependencies in parallel to the component itself (based on the manifest dependencies)

  • The rendering of the Shell can already start while the other files are being loaded asynchronously




Note: manifest first, component-preload later

2. Language fallback causing 404s for properties files


The application I have created is not translated and currently only has one i18n.properties file. I simply do not plan to make this a multi-language application which is quite typical for standalone applications. However, this usually causes an issue when such an application is deployed on HCP since the platform does not perform a so called language fallback on the server.

Let's have a closer look at the network trace again for my i18n file:



Oops. We just spent about 560ms trying to load the file since two additional requests were sent out and caused 404s (which by the way will not be cached and thus hurt our performance every time!).

The reason for this is that SAPUI5 is by default looking primarily at the language set in the browser which in my case happens to be en_US. The runtime will then try to load the best match and in case it does not find this file, falls back to just plain English (en). Since this file is also not part of the deployed application, the last fallback is to load the plain i18n.properties file.

We can easily fix this by chosing our prefered language of choice and setting up our application correctly.

First step, let's rename our i18n file to i18n_en.properties:



Next, let's configure SAPUI5 to only use this language from now on:
	<!-- Bootstrapping UI5 -->
<script id="sap-ui-bootstrap"
src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.m"
data-sap-ui-theme="sap_belize"
data-sap-ui-compatVersion="edge"
data-sap-ui-preload="async"
data-sap-ui-language="en"
data-sap-ui-resourceroots='{"myapp": "."}'>
</script>

Note: data-sap-ui-language="en"

With this in place, let's check out the network trace again:



Alright, much better. And with the latency we just eliminated we just saved between 340 - 520ms startup time (cached respectively uncached behavior).

3. Usage of OData Model V2


The application above already uses the automatic model creation feature based on a configuration in the manifest.json file. Here's the setting:
		"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "myapp.i18n.i18n"
}
},
"": {
"type": "sap.ui.model.odata.ODataModel",
"dataSource": "mainService"
}
},

Note: The type "sap.ui.model.odata.ODataModel" 

The above namespace indicates that an outdated OData Model implementation will be used. This implementation had several defaults which e.g. caused synchronous requests for metadata files and other operations which were changed in the updated implementation which can be used with the corresponding namespace:

sap.ui.model.odata.v2.ODataModel https://sapui5.hana.ondemand.com/sdk/#docs/api/symbols/sap.ui.model.odata.v2.ODataModel.html

Let's see how this affects our timeline:



Note: $metadata is synchronous, no parallel requests or JS processing possible for close to 220ms:



Let's fix this by referencing the right V2 namespace in our manifest.json (alternatively, you can also omit the namespace - it's the default now):
			"": {
"type": "sap.ui.model.odata.v2.ODataModel",
"dataSource": "mainService"
}

Here's the new network trace:



Note: Parallel requests to the $metadata request.

That's 220ms well spent with additional JS processing or parallel requests. Yeah!

4. Use model preload feature


Our OData model needs its metadata - I really cannot do much without it. So it would be beneficial to the overall performance if this request is send as early as possible (we don't want to wait for this request to return later on when we try to load data or render something on the screen).

SAPUI5 has introduced a way to preload a model, effectively causing the metadata request to be sent out earlier than before.

Let's add this to our manifest.json (and make sure you have switched to async component loaded as done before for this to work):
			"": {
"type": "sap.ui.model.odata.v2.ODataModel",
"dataSource": "mainService",
"preload": true
}

Alright, let's see the network trace again:



Note: The $metadata request is issued even before the component preload.

Great! This request can become potentially quite a bottleneck but is now issues as early as possible.

With all of these changes in place, the rednering already feels much smoother. Looking at the current network trace, there is still some smaller enhancement to our app:



Note: Two 404s which must be eliminated.

5. Eliminate all 404s


This step will depend a lot on your application. However, you should strive to understand the reason for every 404 which occurs as part of your application startup and attempt to get rid of it.

Keep in mind: 404s are not cached and their runtime will hit every user every time they start the application, even when all other resources are already in the browser cache.

I have applications waste around 2s due to 6(!) uncached 404s with a latency of roughly 350ms each. Now that is time wasted truly for nothing.

sap.m.Image: Density Awareness

I placed an image in the application content which should display a file called stars.png. SAPUI5 has a great feature by which the current screen resolution will be checked and if a high density screen has been detected, a higher resolution version of a certain image will automatically be loaded.

In my case, I have not provided this version (and I don't plan on doing so). This causes an unecessary request to this high-res version of the image and simply be turned off (densityAware):
	<semantic:FullscreenPage
id="page"
title="{i18n>worklistViewTitle}">
<semantic:content>
<Image src="image/stars.png" height="20px" width="100%" densityAware="false"/>

Northwind read-only: Turn off token handling

Normally, OData operations are always sent to the server using a POST request which makes the usage of an XSRF token necessary for security reasons. Northwind does not support this feature which causes a 501 response. Let's fix this by turning token handling off:
			"": {
"type": "sap.ui.model.odata.v2.ODataModel",
"dataSource": "mainService",
"preload": true,
"settings": {
"tokenHandling": false
}
}

Note: XSRF tokens are required for accessing SAP Gateway Services

 

Conclusion and final performance measurement


Let's have a final look at our cached performance of the application:



Note: Loaded in 1.1s, fully finished in 1.4s (with latency and OData calls).

This loading performance feels great, no more 404s, all files cached except for those which need to be read from the server for data access. Early initial rendering also improves the perceived performance.

Remember: This application loads its index.html from another continent (causing almost 200ms delay) and reads data from the Northwind service, adding another 220ms).

With all of the above in place, applications which do not require an OData call for their initial screen can aim for sub-second initial cached load times. The same is true if the inital screen only requires data which can be bundled in the application preload.
I hope these additional best-practices and hints will help you to further optimize your applications. Let me know in the comments in case you have any questions.

 
9 Comments