javascriptasynchronousasync-awaitxmlhttprequestsapui5

How to avoid "Synchronous XMLHttpRequest on the main thread" warning in UI5?


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?

Update #1:

I've checked the loading with ?sap-ui-xx-nosync=warn and got the following results:

enter image description here

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.

Update #2:

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.


Solution

  • Cause

    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:

    In either case, the good news is that it is still possible to avoid most of the sync XHRs today.

    Resolution

    In order to get rid of sync XHRs in UI5:

    1. 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

    2. 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? .

    3. 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:

        • Ensure that the bootstrap config data-sap-ui-async="true" is added.
        • If the app initiates creating a top-level 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?

    4. 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" ],
        },
        // ...
      });
    5. 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.

    6. 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.

    7. 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.

    Known Issues

    There are, however, still some APIs left which have no asynchronous replacements yet such as:


    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.