写点什么

深入学习 SAP UI5 框架代码系列之一:UI5 Module 的懒加载机制

作者:Jerry Wang
  • 2021 年 11 月 28 日
  • 本文字数:2611 字

    阅读完需:约 9 分钟

深入学习 SAP UI5 框架代码系列之一:UI5 Module 的懒加载机制

什么是 SAP UI5?


SAP UI5 和著名的前端框架三驾马车 React,Angular 和 Vue 一样,是一款前端应用程序开发框架,并且包含了一套适用于企业级前端应用的控件库,是 SAP Fiori 应用的官方首选开发框架。

SAP UI5 基于 Open UI5 开源项目,后者的源代码仓库地址:

https://github.com/SAP/openui5


Jerry 曾经作为 SAP 成都研究院的 Fiori 应用开发人员,从事了将近 3 年的 SAP CRM Fiori 应用开发,在使用 SAP UI5 的过程中,遇到过形形色色的问题,不少都是通过调试 SAP UI5 框架代码自行解决的。平时也会有不少朋友向我咨询开发过程中遇到的和 SAP UI5 相关的问题,所谓授人以鱼不如授人以渔,如果一个 SAP UI5 开发人员对 UI5 框架代码有些许了解,在遇到问题时能够更有针对性更高效地去定位问题。然而 SAP UI5 框架代码浩如烟海,初学者往往鼓起勇气想一探究竟,但却不知道如何下手,最后迷失在 UI5 的源代码海洋里。


Jerry 这个系列,通过 SAP UI5 最简单的 Hello World 应用中最简单的 button 控件出发,试图向大家展示 SAP UI5 框架代码中围绕该控件的相关实现。虽然使用 Fiori Elements,开发人员大多数时候无需手动编写操作 UI5 控件的 JavaScript 代码,然而在遇到 Fiori Elements 不能按照自己的期望工作的时候,如果熟悉 SAP UI5 框架实现,就不至于完全不知所措。


我们首先创建一个只包含一个 Button 控件的 UI5 应用:



浏览器里打开,总共触发了 18 个请求,网络传输流量 1.1MB, 页面总共加载了 5.1MB 资源(见下图底部紫色矩形框所示)。



顺便说一说,为什么页面加载的资源尺寸(5.1 MB)会大于网络传输的数据量(1.1 MB)?


网上有一种说法,页面加载的资源,是通过网络加载的资源,以及从浏览器缓存读取的资源总和,因此会出现 Chrome 开发者工具里显示的页面加载的资源尺寸大于网络传输数据量的情况。


这种说法不完全正确。更准确的说,页面加载资源统计的是前端页面加载的所有资源,经过解压之后的原始大小。


如图,打开 Chrome 开发者工具的 Use Large request rows 选项, 就能显示出经过网络加载资源解压缩过后的原始大小,如下图所示:



以上说明来自 Google 官网:https://developers.google.com/web/tools/chrome-devtools/network/reference#uncompressed


回到我们的 UI5 应用,Ctrl+Alt+Shift+P,选中"Use Debu Sources",让 SAP UI5 加载调试版本的库文件:



待 button 显示在页面之后,打开 Chrome 开发者工具 Sources 面板,能看到 sap/ui 文件夹下多出来一个 commons 文件夹:



回忆一下我们的脚手架应用的代码里,新建了一个命名空间 sap.ui.commons 下的 Button 控件实例:



因此运行时,SAP UI5 对应的 Button Module 会被加载。Button-dbg.js 负责 Button 的生命周期管理和事件响应,ButtonRenderer-dbg.js 负责将 Button 实例渲染成原生的 HTML 代码。



切换到 Network 标签页,选择任意一个 Button Module 加载的网络请求,把鼠标 hover 到 Initiator 列上,在弹出窗口就能看到一个调用栈,从中就能观察到是 index.html 即 Button 控件的消费者,触发了这两个 Button Module 的加载。



在 index.html 里实例化 Button 控件的代码处设置断点,重新刷新应用。因为 sap.ui.commons.Button 并不是原生的 HTML element,所以调试器执行到代码第 11 行并且单步执行后,会触发 Button Module 的加载:



这就是 SAP UI5 Module 的懒加载机制:如果该页面没有用到 Button 控件,则对应的 Button Module 永远不会被加载。


下图 sap-ui-core-dbg.js 第 26384 行就是 Button Module 的加载入口,注意注释里 lazy stub for XXX 的提示:



requireModule 准备加载 sap/ui/commons/button.js 这个 Module 文件:



Module 文件通过 AJAX 被加载后,SAP UI5 得到的只是纯字符串文本,还无法直接用其创建 button 实例。SAP UI5 会调用浏览器原生 API, window.eval(), 将 button.js 文件的字符串内容传入该 API,执行结果是一个 JavaScript 对象,也就是 SAP UI5 Button Module 的运行时实体。


SAP UI5 运行时为所有的 Module 维护了一个注册表,以键值对的数据结构存储了这些 Module 的信息,键的数据类型为 string,值类型即 window.eval()执行加载好的 JavaScript 文件内容后返回的 JavaScript 对象。


Module 的可能状态为一系列枚举值:INITIAL, LOADED, READY, FAILED, PRELOADED.


回到我的例子,因为我的代码触发了 Button Module 的第一次加载,所以代码第 16487 行,将 Module 的状态标注为 INITIAL.



继续调试:


  • Line 16514: 将 Button Module 状态设置为 LOADING.

  • Line 16517: 根据全局标志位 window.sap-ui-loaddbg 的值决定加载 Button Module 的普通版本还是调试版本。

  • Line 16520: 根据 Module 名称获得待加载 Module 的 url.

  • Line 16525: 使用 jQuery.AJAX 加载 Button-dbg.js.



因为该 Module 若不加载完成,则我们代码里的 new sap.ui.commons.Button 无法继续下去,因此这里的 AJAX 调用以同步模式进行( async = false ). 在其成功加载的回调函数里,将 Module 状态设置为 LOADED, response 变量包含的就是 Button-dbg.js 的文本内容。


Module 状态为 LOADED,说明其文本内容已经加载完成,可以交给 16543 行的 execModule 函数执行了(注意该函数上面的 IF 条件)。



代码第 16612,如调试器所示:变量 sScript 包含的就是 Button-dbg.js 的文本内容,待 window.eval()执行完毕后,Module 的状态设置为 READY:



new sap.ui.commons.button 这行语句看似仅仅是一个简单的实例构造操作,背后却隐藏着 SAP UI5 控件设计的思路。


SAP UI5 的注释写的很清楚:首先用工厂方法创建一个新的空 Button 实例 oInstance,然后再使用消费者调用 new sap.ui.commons.Button 时传入的参数对 oInstance 进行 enrich:



我们查看 Button Module 的源代码,发现通过 JavaScript 的原型继承,Button 的 prototype 为 Control:



查看 SAP UI5 官网上对 sap.ui.core.Control 的说明:


  • Rendering: 每个 SAP UI5 控件都有对应的 Renderer,被 RenderManager 调用负责生成原生的 HTML 代码。

  • 显示/隐藏,Busy Indicator,支持关联自定义的 CSS 样式类,注册浏览器事件。



Control 的原型是 Element:



Element 是 SAP UI5 页面的基本元素,主要用于 UI5 的内部实现。



Element 的原型是 ManagedObject:



因为这条原型链过长,Jerry 就不一一截图了,大家只需要记住结论:从 Button 控件出发,沿着它的原型链往上回溯,最后会到达 BaseObject(相当于 ABAP/Java 里的 Object).

Button->Control->Element->ManagedObject->EventProvider->BaseObject.

因此,在执行 Button 自己的构造函数之前,其原型链上每个节点的构造函数会依次执行一次:



本系列下一篇文章:UI5 控件渲染机制,我们会介绍 SAP UI5 控件是如何渲染出最终呈现在浏览器里的原生 HTML 代码的。

发布于: 4 小时前阅读数: 12
用户头像

Jerry Wang

关注

个人微信公众号:汪子熙 2017.12.03 加入

SAP成都研究院开发专家,SAP社区导师,SAP中国技术大使。

评论

发布
暂无评论
深入学习 SAP UI5 框架代码系列之一:UI5 Module 的懒加载机制