如何找到 slow-loading SAPUI5 应用程序的加载瓶颈
How to find loading bottleneck of a slow-loading SAPUI5 app
我正在构建一个自定义 SAPUI5 应用程序,它包含页面 header 内容中的七个图表 (sap.viz.ui5.controls.VizFrame
)(嵌套在 sap.suite.ui.commons.ChartContainer
中)和一个网格 table (sap.ui.table.Table
) 在主要内容区域。图表和 table 的数据由 OData V2 服务提供,应用程序在最新版本 (1.81.0) 上为 运行 stand-alone。
问题是应用程序加载时间过长。这需要 7 到 20 秒。这对于“更复杂”的应用程序来说是否常见?我试图找到瓶颈,但一切看起来都很好。许多网络请求都被缓存(它们需要 0 毫秒),但是,它们之间有轻微的延迟,我不明白为什么。此外,尽管我在我的 index.html
文件中使用 data-sap-async="true"
,但控制台中有以下警告:
[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/. [syncXHRFix-dbg.js:211:15]
我的 index.html 和 manifest.json
的代码片段
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Loading - Customer Fact Sheet</title>
<script id="sap-ui-bootstrap"
src="resources/sap-ui-core.js"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-resourceroots='{"com.schott.fiori.customerfactsheet.customerfactsheet-fiori3": "./"}'
data-sap-ui-compatVersion="edge"
data-sap-ui-oninit="module:sap/ui/core/ComponentSupport"
data-sap-ui-async="true"
data-sap-ui-frameOptions="trusted">
</script>
<link href="https://www.schott.com/static/assets/gfx/favicon/SCHOTT_16.png" rel="shortcut icon" type="image/png" />
</head>
<body class="sapUiBody">
<div data-sap-ui-component data-name="com.schott.fiori.customerfactsheet.customerfactsheet-fiori3" data-id="container" data-settings='{"id" : "customerfactsheet-fiori3"}'></div>
</body>
</html>
{
"_version": "1.12.0",
"sap.app": {
"id": "com.schott.fiori.customerfactsheet.customerfactsheet-fiori3",
"type": "application",
"i18n": "i18n/i18n.properties",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"sourceTemplate": {
"id": "servicecatalog.connectivityComponentForManifest",
"version": "0.0.0"
},
"dataSources": {
"YODATA_SD_CFS_MATRIX_SRV": {
"uri": "/sap/opu/odata/sap/YODATA_SD_CFS_MATRIX_SRV/",
"type": "OData",
"settings": {
"localUri": "localService/metadata.xml"
}
}
}
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone@2": "",
"tablet": "",
"tablet@2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
},
"sap.ui5": {
"flexEnabled": false,
"rootView": {
"viewName": "com.schott.fiori.customerfactsheet.customerfactsheet-fiori3.view.Main",
"type": "XML",
"async": true,
"id": "Main"
},
"dependencies": {
"minUI5Version": "1.65.6",
"libs": {
"sap.ui.layout": {},
"sap.ui.core": {},
"sap.m": {}
}
},
"contentDensities": {
"compact": true,
"cozy": false
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "com.schott.fiori.customerfactsheet.customerfactsheet-fiori3.i18n.i18n"
}
},
"": {
"type": "sap.ui.model.odata.v2.ODataModel",
"settings": {
"defaultOperationMode": "Client",
"defaultBindingMode": "OneWay",
"defaultCountMode": "Request"
},
"dataSource": "YODATA_SD_CFS_MATRIX_SRV",
"preload": true
}
},
"resources": {
"css": [{
"uri": "css/style.css"
}]
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "com.schott.fiori.customerfactsheet.customerfactsheet-fiori3.view",
"controlAggregation": "pages",
"controlId": "app",
"clearControlAggregation": false
},
"routes": [{
"name": "RouteMain",
"pattern": "RouteMain",
"target": ["TargetMain"]
}],
"targets": {
"TargetMain": {
"viewType": "XML",
"transition": "slide",
"clearControlAggregation": false,
"viewId": "Main",
"viewName": "Main"
}
}
}
},
"sap.platform.hcp": {
"uri": "webapp",
"_version": "1.1.0"
}
}
我的网络选项卡的屏幕截图
如“网络”选项卡所示,有许多模块按顺序一一加载,其中许多甚至通过同步 XHR 加载。最重要的任务是尽可能减少同步 XHR。
我在manifest.json
中看到只声明了少量库。然而,根据“网络”选项卡,该应用程序使用来自其他库的控件,这些库未在 dependencies
.
中声明
所以应该是:
"sap.ui5": {
"dependencies": {
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.ui.table": {},
"sap.f": {},
"sap.ui.unified": {},
"sap.ui.layout": {},
"sap.viz": {},
"sap.suite.ui.commons": {}
},
一些库被其他库传递地需要(例如 sap.ui.table
需要 sap.ui.unified
)。src 你可能如果该库未直接使用,则添加 "sap.ui.unified": { lazy: true }
。
预先异步预加载通常通过 loadSyncXHR
.
加载的第三方模块
如果您检查“网络”选项卡中的 Initiator 列,您可以检测到更多通过同步 XHR 加载的模块。将这些模块添加到 data-sap-ui-modules
应该避免它:
<script id="sap-ui-bootstrap"
data-sap-ui-modules="sap/ui/thirdparty/datajs,sap/ui/thirdparty/require"
...>
v2.ODataModel
需要 sap/ui/thirdparty/datajs
。 sap/ui/thirdparty/require
模块由 sap.viz
库提供。这两个模块通常都是通过 loadSyncXHR
获取的。上面的代码片段修复了它。您可能会找到更多这样的模块。
总的来说,以上几点应该已经显着改善了初始加载时间。有关更多性能指南,请查看 Performance Checklist.
其他需要考虑的事情
I18n
为了减少请求数量如果该应用仅针对使用相同语言的特定人群,请考虑完全放弃 i18n 支持。多个请求
i18n 文本包不仅体积大,而且在加载时会阻塞其他请求,因为默认情况下它们也是通过同步 XHR 加载的。 是一种异步加载它们并指定应用程序支持哪些语言环境的方法,但这是另一个主题。
OData 模型
如果不需要,请考虑将计数模式设置为 None
,因为 $count
计算在后端的成本往往很高。此外,操作模式 Client
会获取所有实体。考虑 lazy-load 他们。
对于所有聚合绑定
"": {
"dataSource": "MyV2Source",
"settings": {
"defaultOperationMode": "Default",
"defaultCountMode": "None",
"defaultBindingMode": "TwoWay",
"preliminaryContext": true
},
"preload": true
},
关于preliminaryContext
:参见Optimizing Dependent Bindings。
对于单个聚合绑定
items: { // e.g.
path: '/MySet',
parameters: {
countMode: 'None',
operationMode: 'Client' | 'Default' | 'Server' (see API ref)
}
}
API参考:https://openui5.hana.ondemand.com/api/sap.ui.model.odata.v2.ODataListBinding
UI5 工具
在部署应用程序之前,通过以下命令构建应用程序应该会大大减少应用程序的大小:
ui5 build self-contained -a
来自https://github.com/SAP/openui5-sample-app#option-2-self-contained-build
这目前仅适用于 stand-alone 个应用。
我正在构建一个自定义 SAPUI5 应用程序,它包含页面 header 内容中的七个图表 (sap.viz.ui5.controls.VizFrame
)(嵌套在 sap.suite.ui.commons.ChartContainer
中)和一个网格 table (sap.ui.table.Table
) 在主要内容区域。图表和 table 的数据由 OData V2 服务提供,应用程序在最新版本 (1.81.0) 上为 运行 stand-alone。
问题是应用程序加载时间过长。这需要 7 到 20 秒。这对于“更复杂”的应用程序来说是否常见?我试图找到瓶颈,但一切看起来都很好。许多网络请求都被缓存(它们需要 0 毫秒),但是,它们之间有轻微的延迟,我不明白为什么。此外,尽管我在我的 index.html
文件中使用 data-sap-async="true"
,但控制台中有以下警告:
[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/. [syncXHRFix-dbg.js:211:15]
我的 index.html 和 manifest.json
的代码片段<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Loading - Customer Fact Sheet</title>
<script id="sap-ui-bootstrap"
src="resources/sap-ui-core.js"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-resourceroots='{"com.schott.fiori.customerfactsheet.customerfactsheet-fiori3": "./"}'
data-sap-ui-compatVersion="edge"
data-sap-ui-oninit="module:sap/ui/core/ComponentSupport"
data-sap-ui-async="true"
data-sap-ui-frameOptions="trusted">
</script>
<link href="https://www.schott.com/static/assets/gfx/favicon/SCHOTT_16.png" rel="shortcut icon" type="image/png" />
</head>
<body class="sapUiBody">
<div data-sap-ui-component data-name="com.schott.fiori.customerfactsheet.customerfactsheet-fiori3" data-id="container" data-settings='{"id" : "customerfactsheet-fiori3"}'></div>
</body>
</html>
{
"_version": "1.12.0",
"sap.app": {
"id": "com.schott.fiori.customerfactsheet.customerfactsheet-fiori3",
"type": "application",
"i18n": "i18n/i18n.properties",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"sourceTemplate": {
"id": "servicecatalog.connectivityComponentForManifest",
"version": "0.0.0"
},
"dataSources": {
"YODATA_SD_CFS_MATRIX_SRV": {
"uri": "/sap/opu/odata/sap/YODATA_SD_CFS_MATRIX_SRV/",
"type": "OData",
"settings": {
"localUri": "localService/metadata.xml"
}
}
}
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone@2": "",
"tablet": "",
"tablet@2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
},
"sap.ui5": {
"flexEnabled": false,
"rootView": {
"viewName": "com.schott.fiori.customerfactsheet.customerfactsheet-fiori3.view.Main",
"type": "XML",
"async": true,
"id": "Main"
},
"dependencies": {
"minUI5Version": "1.65.6",
"libs": {
"sap.ui.layout": {},
"sap.ui.core": {},
"sap.m": {}
}
},
"contentDensities": {
"compact": true,
"cozy": false
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "com.schott.fiori.customerfactsheet.customerfactsheet-fiori3.i18n.i18n"
}
},
"": {
"type": "sap.ui.model.odata.v2.ODataModel",
"settings": {
"defaultOperationMode": "Client",
"defaultBindingMode": "OneWay",
"defaultCountMode": "Request"
},
"dataSource": "YODATA_SD_CFS_MATRIX_SRV",
"preload": true
}
},
"resources": {
"css": [{
"uri": "css/style.css"
}]
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "com.schott.fiori.customerfactsheet.customerfactsheet-fiori3.view",
"controlAggregation": "pages",
"controlId": "app",
"clearControlAggregation": false
},
"routes": [{
"name": "RouteMain",
"pattern": "RouteMain",
"target": ["TargetMain"]
}],
"targets": {
"TargetMain": {
"viewType": "XML",
"transition": "slide",
"clearControlAggregation": false,
"viewId": "Main",
"viewName": "Main"
}
}
}
},
"sap.platform.hcp": {
"uri": "webapp",
"_version": "1.1.0"
}
}
我的网络选项卡的屏幕截图
如“网络”选项卡所示,有许多模块按顺序一一加载,其中许多甚至通过同步 XHR 加载。最重要的任务是尽可能减少同步 XHR。
我在
manifest.json
中看到只声明了少量库。然而,根据“网络”选项卡,该应用程序使用来自其他库的控件,这些库未在dependencies
.
中声明 所以应该是:"sap.ui5": { "dependencies": { "libs": { "sap.ui.core": {}, "sap.m": {}, "sap.ui.table": {}, "sap.f": {}, "sap.ui.unified": {}, "sap.ui.layout": {}, "sap.viz": {}, "sap.suite.ui.commons": {} },
一些库被其他库传递地需要(例如
sap.ui.table
需要sap.ui.unified
)。src 你可能如果该库未直接使用,则添加"sap.ui.unified": { lazy: true }
。预先异步预加载通常通过
加载的第三方模块loadSyncXHR
.如果您检查“网络”选项卡中的 Initiator 列,您可以检测到更多通过同步 XHR 加载的模块。将这些模块添加到
data-sap-ui-modules
应该避免它:<script id="sap-ui-bootstrap" data-sap-ui-modules="sap/ui/thirdparty/datajs,sap/ui/thirdparty/require" ...>
v2.ODataModel
需要sap/ui/thirdparty/datajs
。sap/ui/thirdparty/require
模块由sap.viz
库提供。这两个模块通常都是通过loadSyncXHR
获取的。上面的代码片段修复了它。您可能会找到更多这样的模块。
总的来说,以上几点应该已经显着改善了初始加载时间。有关更多性能指南,请查看 Performance Checklist.
其他需要考虑的事情
I18n
为了减少请求数量如果该应用仅针对使用相同语言的特定人群,请考虑完全放弃 i18n 支持。多个请求 i18n 文本包不仅体积大,而且在加载时会阻塞其他请求,因为默认情况下它们也是通过同步 XHR 加载的。 是一种异步加载它们并指定应用程序支持哪些语言环境的方法,但这是另一个主题。
OData 模型
如果不需要,请考虑将计数模式设置为 None
,因为 $count
计算在后端的成本往往很高。此外,操作模式 Client
会获取所有实体。考虑 lazy-load 他们。
对于所有聚合绑定
"": {
"dataSource": "MyV2Source",
"settings": {
"defaultOperationMode": "Default",
"defaultCountMode": "None",
"defaultBindingMode": "TwoWay",
"preliminaryContext": true
},
"preload": true
},
关于preliminaryContext
:参见Optimizing Dependent Bindings。
对于单个聚合绑定
items: { // e.g.
path: '/MySet',
parameters: {
countMode: 'None',
operationMode: 'Client' | 'Default' | 'Server' (see API ref)
}
}
API参考:https://openui5.hana.ondemand.com/api/sap.ui.model.odata.v2.ODataListBinding
UI5 工具
在部署应用程序之前,通过以下命令构建应用程序应该会大大减少应用程序的大小:
ui5 build self-contained -a
来自https://github.com/SAP/openui5-sample-app#option-2-self-contained-build
这目前仅适用于 stand-alone 个应用。