Skip to Content

Inspired by following blogs/posts:

Why I want my Fiori to run like a Ferrari

SAPUI5 Mobile Splash Screen

SAPUI5 Content Compression

With a SAPUI5 mobile working via 3G you may need to wait up to a couple of seconds, before you get a first screen of the app. The reason is, that SAPUI5 is relative heavy library and need to load some megabytes of data to start working.

If you check the most of sapui5 examples – you’ll see something like

/wp-content/uploads/2013/12/0002_348773.png

This code will be processed by your browser as followed.

PR.001.png

SAPUI5 content consists of 2 libraries: sap.ui.commons and sap.m. That’s why library-preload.json, library.css and library-parameters.json loaded 2 times.

In the browser it looks like

/wp-content/uploads/2013/12/0003_348775.png

Blue vertical line at almost 2 seconds mean the user will first see some content after loading about 500KB and 2 seconds awaiting (even more on mobile device with 3G).

The idea to show the loading screen as soon as possible to the user, and load SAPUI5 stuff after that. If user have to wait a couple of seconds before start to work – you may want to show some kind of a loading progress. For example, first show a spinner and then a content.

/wp-content/uploads/2013/12/spinner_348782.gif

I desided to move all js code into a separate file application.js and include a spinner js code from github.

App logic should look as following

PR.003.png

First page load time should reduce from 2+ seconds to 100-200 milliseconds. Initial load size from 500 KB should reduce to about 5 KB.

So, the new index.html consists of 3 js scripts: spinner, application.js and call of initialization.

/wp-content/uploads/2013/12/0006_348784.png

And now the magic begins. There is no loading of SAPUI5 here.

Let’s check the code of application.js.


oApplication = { // Application is an object
  views: {}, // Application views
  load: function(src, id, libs, theme, callback) {
  var opts = {
  length: 12, // The length of each line
  width: 4, // The line thickness
  radius: 12, // The radius of the inner circle
  };
  var target = document.getElementById('content');
  this.spinner = new Spinner(opts).spin(target);
  setTimeout(this.loadSAPUI5(src, id, libs, theme, callback));
  },
  loadSAPUI5: function (src, id, libs, theme, callback)
  {
  var s,r,t;
  r = false;
  s = document.createElement('script');
  s.type = 'text/javascript';
  s.src = src;
  s.id = id;
  s.setAttribute("data-sap-ui-libs", libs);
  s.setAttribute("data-sap-ui-theme", theme);
  s.onload = s.onreadystatechange = function() {
      //console.log( this.readyState ); //uncomment this line to see which ready states are called.
  if ( !r && (!this.readyState || this.readyState == 'complete') ){
  r = true;
  callback();
  }
  };
  t = document.getElementsByTagName('script')[0];
  t.parentElement.insertBefore(s, t);
  },
  onSAPUI5Loaded: function(){
  oApplication.initializeUI5();
  $("body").fadeOut("slow",function(){
  $("#content").empty();
  $("#content").removeAttr('style');
  oApplication.app.placeAt("content");
  $(this).fadeIn("slow");
  });
  },
  initializeUI5: function(){
  var oApp = new sap.m.App( "mApp" );
  var oPage = new sap.m.Page({
  id : "mPage", // sap.ui.core.ID
  title : "Mobile page", // string
  showFooter : false, // boolean, since 1.13.1
  });
  var oContent = new sap.m.ObjectHeader({
  id : "mObjHeader", // sap.ui.core.ID
  title : "Title", // string
  number : "250", // string
  numberUnit : "EUR", // string
  markFavorite : true, // boolean, since 1.16.0
  markFlagged : true, // boolean, since 1.16.0
  showMarkers : true, // boolean, since 1.16.0
  attributes : [ new sap.m.ObjectAttribute({
  id : "mAttribute", // sap.ui.core.ID
  visible : true, // boolean
  text : "This is a test attribute of ObjectHeader", // string
  }) ], // sap.m.ObjectAttribute
  });
  oPage.addContent(oContent);
  oApp.addPage(oPage);
  this.app = oApp;
  }
}




So, whole file is a definition of the js object, which has following methods

load – to call from index.html

loadSAPUI5 – to include SAPUI5 into document and load if asynchronously

onSAPUI5Loaded – to hide a spinner and show the app

initializeUI5 – to create SAPUI5 user interface (consists of the code from previous version of index.html).

Logic look like

PPR.001.png

LoadSAPUI5 is called asynchronously from oApplication.load via setTimeout() function. If you test your app in browser – you’ll get following.

/wp-content/uploads/2013/12/0004_348786.png

at the bottom of page you can see, that DOMContentLoaded is in 21 ms (it’s due to local test) with 3 files. Let’s upload it to the hosting and make a fair test.

/wp-content/uploads/2013/12/0007_348787.png

So, before show the application is just 5kb size and 146ms time.

In comparison with the first test:

Diagram.png

Example on jsbin.

P.S.: This idea helps to speedup only a first application response. SAPUI5 libraries have to be loaded in any case. Synchron or asynchron – it’s your choice.

P.P.S.:  English language is not my native language, and any person is not insured from mistakes and typing errors. If you have found an error in the text, please let me know – I’ll correct the post.

P.P.P.S.: If you have some ideas, how to correct/improve this post – please don’t hesitate to leave a comment.

To report this post you need to login first.

23 Comments

You must be Logged on to comment or reply to a post.

  1. Prabaharan Asokan

    Thanks for the great blog..

     

    I see “sap-ui-core.js” has been compressed in your screenprint. But on testing this demo POA app the same core js file is not compressed(still 396 KB). Can you suggest?

    SAP-UI-Core.png

     

    Thanks

    Prabaharan

    (0) 
      1. Prabaharan Asokan

        Hi

        I disabled web security in chrome browser for overcoming cross origin requests to test some apps. Also in my corporate antivirus has Been installed and I don’t know whether we work via proxy.

         

        Lastly I checked in my personal pc , and I had less responsive times like you had.

         

        Thanks for the help.

         

        Prabaharan

        (0) 
  2. Jason Scott

    Just wondering if this is still working for you? Doesn’t work for me locally; nor when I use the jsbin provided (with Chrome and IE9). It seems that the onload event for the inserted script gets fired BEFORE the script has executed and therefore “initializeUI5()” method fails.

     

    There is another method – simpler but there is still a small delay… You can load the UI library by specifying data-sap-ui-preload=async in the bootstrap. Then add a script tag at the bottom of the html body and attach to the cores Init event. In here you can access all the UI5 functions and effectively start your app. Before the event is fired you can display anything else in the body, including the spinner you’ve used.

    (0) 
    1. Konstantin Anikeev Post author

      Hi Jason,

       

      works fine for me (Chrome, Firefox, IE11)… try the address http://ui5.anikeev.eu/

      I’m not sure the data-sap-ui-preload=async works the same way.

      At least the core should be preloaded synchron, what is already almost 0,5 MB

       

      Regards

      Konstantin

      (0) 
      1. Jason Scott

        This website does work for me on my mac at home. No matter what I do it will not work for me on Chrome or IE9 on my Windows laptop at work. Weird. Thanks anyway…

        The other method that I specified in the previous comment also works well. You are correct that the core loads synchronously from its header script tag; however all the library modules load asynchronously. So you get a smaller delay waiting for the core and you can show a spinner or splash page and then on the core init event you can display you UI5 app.

        (0) 
        1. Jason Scott

          oh I should add as well… that I’ve found using preload=async actually gives a faster app load time. Considerably faster on a desktop in Chrome. I wonder how it would go in a container like cordova…

          (0) 
          1. Konstantin Anikeev Post author

            Hi Jason,

             

            may you could write a blog post about your investigations. It would be interesting for me. and sure not only for me.

             

            Regards

            Konstantin

            (0) 
        2. Konstantin Anikeev Post author

          The other method that I specified in the previous comment also works well. You are correct that the core loads synchronously from its header script tag; however all the library modules load asynchronously. So you get a smaller delay waiting for the core and you can show a spinner or splash page and then on the core init event you can display you UI5 app.

          not sure about that. AFAIK js is a “single thread” language. It means, it loads initially all static defined scripts and only then (after DOMContentLoaded) starts execution.

           

          If you use static script tag even with async preload of libraries your spinner should not start before SAPUI5 Core is loaded.

          (0) 
          1. Jason Scott

            No its not XSS. I use those hana.ondemand.com sources all the time.

             

            Its some sort of bug in the browsers. From my research relying on the onload event (chrome) or onreadystatechange event (IE < 10) on older browsers – even just a year or two old) is unpredictable.

            jQuery caters for it better. However to use jQuery before sapui5 is loaded would mean separately loading the jQuery library and then using the NoJquery sapui5 sources.

             

            I upgrade chrome to the latest portable edition for windows (33) and it works fine. My previous version on teh windows laptop was 26 and the onload event when inserting a script fires immediately after its been placed into the document instead of after the javascript has executed. This causes the page load to fail. The same issue happens in IE9. this is fixed in IE10 I believe.

             

            Stack Overflow answers to these script-onload issues are to simple call your callback function from inside the script but this is not possible for us as sap as we dont want to edit sap-ui-core.js.

             

            So… beware if using IE9 or Chrome 26!

             

            Regards…Jason.

            (0) 
  3. Siyu Henningsen

    Hi Konstantin,

     

    Thanks for putting this together, I followed this blog and got the spinner running. But I found now, if I add parameter in the URL: ?sap-ui-debug=true.

    I got below error message:

     

    2014-10-02 18:03:57 Device API logging initialized – DEVICE

    Failed to execute ‘write’ on ‘Document’: It isn’t possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened.

     

    Do you have the same issue? I tried version 1.22.4, 1.24.1 even 1.25.0-SNAPSHOT.

     

    Best Regards,

    Siyu

    (0) 
    1. Michael Luther

      In case anybody is still interested in this, I just needed to dig into that issue myself as well.

       

      The problem is the way sap-ui-core.js loads the debug-files. It does so by doing document.write(“<script src=”sap-ui-core-dbg.js” />”); which asynchroniously loaded files cannot do.

       

      The work-around for me was to beautify sap-ui-core.js and modify it. The trick is to add the script-tag to the body specifically rather than to say document.write:

       

                     //document.write(“<script type=\”text/javascript\” src=\”” + D + “\”></script>”);

       

                      var scriptTag = document.createElement(“script”);

       

                      scriptTag.type = “text/javascript”;

       

                      scriptTag.src = D;

       

                      document.body.appendChild(scriptTag);

       

      This is alright for me, since I develop locally and provision the library via bower.

       

      In case you are interested, I put the file onto github.You can pick it up here.

       

      Edit:

      Since the initial script is loaded but does not load the library, I do not bind an event handler to the readystate of the script-tag, but go:

       

           this.ui5LoadingChecker = window.setInterval(function(){

       

       

       

                  if(sap.ui.core){

       

                      self.initializeUI5();

       

                      clearInterval(self.ui5LoadingChecker);

       

              }, 1000);

       

      Hope this helps.

       

      Cheers

      Michel

      (0) 
  4. Ameya Pimpalgaonkar

    Hi Konstantin,

     

    Extremely helpful post! great to see you taking efforts to put this across. I wanted to ask if you can post lifecylce hooks sequence of a typical UI5 application? That’d be great.

     

    I shall try this example and reply in case I face any problems. Thanks again, great work!!

     

    Ameya

    (0) 
  5. Vince Tebano

    The settimeout does not seem to work in IE.  Specially in IE9.

     

    The statement: setTimeout(this.loadSAPUI5(src, id, libs, theme, callback));  does not seem to work because IE is stating that there is an invalid argument.

    (0) 

Leave a Reply