本文是深刻学习 SAP UI5 框架代码系列的第二篇文章。
系列目录
- SAP UI5 利用开发人员理解 UI5 框架代码的意义
- UI5 module 懒加载机制
- UI5 控件渲染机制
- HTML 原生事件 VS SAP UI5 Semantic 事件
- UI5 控件元数据实现细节
- UI5 控件的实例数据实现细节
- UI5 控件数据绑定的实现原理
- UI5 控件数据绑定的三种模式:One Way,Two Way 和 OneTime 实现原理比拟
- UI5 控件 ID 的生成逻辑
- UI5 控件的多语言 (国际化,Internationalization,i18n) 反对的实现原理
- XML 视图里的 button 控件
- button 控件和它背地的 DOM 元素
通过 Jerry 前一篇文章 一个用于 SAP UI5 学习的脚手架利用,没有任何后盾 API 的依赖 介绍的脚手架利用,创立一个只蕴含一个 Button 控件的 UI5 利用:
浏览器里关上,总共触发了 18 个申请,网络传输流量 1.1MB, 页面总共加载了 5.1MB 资源(见下图底部紫色矩形框所示)。
顺便说一说,为什么页面加载的资源尺寸 (5.1 MB) 会大于网络传输的数据量(1.1 MB)?
网上有一种说法,页面加载的资源,是通过网络加载的资源,以及从浏览器缓存读取的资源总和,因而会呈现 Chrome 开发者工具里显示的页面加载的资源尺寸大于网络传输数据量的状况。
这种说法不完全正确。更精确的说,页面加载资源统计的是前端页面加载的所有资源,通过解压之后的原始大小。
如图,关上 Chrome 开发者工具的 Use Large request rows 选项, 就能显示出通过网络加载资源解压缩过后的原始大小,如下图所示:
以上阐明来自 Google 官网:
https://developers.google.com…
回到咱们的 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 控件渲染机制。
感激浏览。
更多 Jerry 的原创文章,尽在:” 汪子熙 ”: