许多类在使用配置对象创建(实例化)类时都有快捷名称。快捷名称称为 alias
(或如果类扩展了 Ext.Component,则称为 xtype
)。别名/xtype 列在适用类的类名旁边,以便快速参考。
框架类或其成员可以指定为 private
或 protected
。否则,类/成员为 public
。Public
、protected
和 private
是访问描述符,用于传达应该如何以及何时使用类或类成员。
Public 类和类成员可供任何其他类或应用程序代码使用,并且可以在主要产品版本中作为稳定且持久的内容依赖。公共类和成员可以通过子类安全地扩展。
Protected 类成员是稳定的 public
成员,旨在由拥有类或其子类使用。受保护的成员可以通过子类安全地扩展。
Private 类和类成员在框架内部使用,不供应用程序开发人员使用。私有类和成员可能会随时更改或从框架中省略,恕不另行通知,并且不应在应用程序逻辑中依赖。
static
标签。 *请参阅下面的静态。下面是一个示例类成员,我们可以对其进行剖析,以显示类成员的语法(在本例中是从 Ext.button.Button 类查看的 lookupComponent 方法)。
让我们看一下成员行的每个部分
lookupComponent
)( item )
)Ext.Component
)。对于不返回任何内容(而不是 undefined
)的方法,或者可能显示为由正斜杠 /
分隔的多个可能值,表示返回的内容可能取决于方法调用的结果(即,如果 get 方法调用成功,则方法可能返回 Component,如果失败,则返回 false
,这将显示为 Ext.Component/Boolean
)。PROTECTED
- 请参阅下面的标志部分)Ext.container.Container
)。如果成员源自当前类,则源类将显示为蓝色链接;如果成员从祖先类或混入类继承,则显示为灰色。view source
)item : Object
)。undefined
之外的值,则“返回值”部分将注释返回的类或对象的类型以及描述(示例中为 Ext.Component
)Available since 3.4.0
- 未在示例中显示),就在成员描述之后Defaults to: false
)API 文档使用许多标志来进一步传达类成员的功能和意图。标签可以用文本标签、缩写或图标表示。
classInstance.method1().method2().etc();
false
,则标记为可阻止的事件将不会触发- 表示框架类
- Singleton 框架类。 *有关更多信息,请参阅 singleton 标志
- 组件类型框架类(Ext JS 框架中扩展 Ext.Component 的任何类)
- 表示类、成员或指南在当前查看的版本中是新的
- 表示类型为 config
的类成员
- 表示类型为 property
的类成员
- 表示类型为 method
的类成员
- 表示类型为 event
的类成员
- 表示类型为 theme variable
的类成员
- 表示类型为 theme mixin
的类成员
- 表示类、成员或指南在当前查看的版本中是新的
在 API 文档页面上的类名正下方是一行按钮,对应于当前类拥有的成员类型。每个按钮都显示按类型划分的成员计数(此计数在应用过滤器时更新)。单击按钮将导航到该成员部分。将鼠标悬停在成员类型按钮上将显示该类型的所有成员的弹出菜单,以便快速导航。
与类配置选项相关的 Getter 和 Setter 方法将在方法部分以及 API 文档和成员类型菜单的配置部分中显示,就在它们使用的配置下方。Getter 和 Setter 方法文档将在配置行中找到,以便于参考。
您的页面历史记录保存在本地存储中,并显示在顶部标题栏的正下方(使用可用的实际空间)。默认情况下,显示的唯一搜索结果是与您当前查看的产品/版本匹配的页面。您可以通过单击历史记录栏右侧的 按钮并选择“全部”单选按钮来扩展显示的内容。这将显示所有产品/版本历史记录栏中的所有最近页面。
在历史记录配置菜单中,您还将看到最近访问页面的列表。结果按“当前产品/版本”和“全部”单选按钮过滤。单击 按钮将清除历史记录栏以及保存在本地存储中的历史记录。
如果在历史记录配置菜单中选择“全部”,则将启用“在历史记录栏中显示产品详细信息”的复选框选项。选中后,每个历史页面的产品/版本将在历史记录栏中与页面名称一起显示。将光标悬停在历史记录栏中的页面名称上也会将产品/版本显示为工具提示。
可以使用页面顶部的搜索字段搜索 API 文档和指南。
在 API 文档页面上,还有一个过滤器输入字段,用于使用过滤器字符串过滤成员行。除了按字符串过滤外,您还可以按访问级别、继承和只读过滤类成员。这是通过使用页面顶部的复选框完成的。
API 类导航树底部的复选框过滤类列表,以包含或排除私有类。
单击空的搜索字段将显示您最近 10 次搜索,以便快速导航。
每个 API 文档页面(Javascript 原始类型页面除外)都有一个菜单视图,其中包含与该类相关的元数据。此元数据视图将具有以下一项或多项
Ext.button.Button
类具有 Ext.Button
的备用类名)。备用类名通常为了向后兼容性而维护。可运行的示例 (Fiddles) 默认在页面上展开。您可以使用代码块左上角的箭头单独折叠和展开示例代码块。您还可以使用页面右上角的切换按钮切换所有示例的折叠状态。所有切换状态将在页面加载之间记住。
类成员默认在页面上折叠。您可以使用成员行左侧的箭头图标或全局使用右上角的展开/折叠所有切换按钮来展开和折叠成员。
在较窄的屏幕或浏览器上查看文档将导致针对较小外形尺寸优化的视图。桌面视图和“移动”视图之间的主要区别在于
可以通过单击 API 文档页面顶部的类名来查看类源代码。可以通过单击成员行右侧的“view source”链接来查看类成员的源代码。
“内存泄漏”一词在许多上下文中使用。它通常用于描述内存增长。维基百科将“内存泄漏”定义为
“当计算机程序错误地管理内存分配时”。
这是一个合理的定义,但有点模糊。
就本指南而言,内存泄漏定义为
在重复一段代码后,内存使用量无限制增长时。代码必须重复“到耗尽”(足以需要回收内存),并且代码还必须确保已执行合理的语言/框架清理。
这有点拗口,所以让我们分解这个定义的重要部分
根据程序运行的环境,通常有一些关于您应该采取的操作的规则,以表明您已完成对某个已分配内存块的使用。在 Ext JS 中,这通常是 destroy 方法,它通常会清理 DOM 元素并取消绑定监听器。
在 C# 中,推荐的模式是 IDisposable 接口。无论平台如何,都必须遵循这些约定,以允许平台释放已分配的资源。如果未遵循清理程序,则会导致内存泄漏,因为无法自动推断何时不再需要资源。
假设有一台开发机器,具有 64Gb 的可用内存。一段代码运行 5 次。通过检查,注意到每次运行后,内存使用量每次增加 1Mb,并且永远不会回收。
这种观察结果实际上并不表示有问题。该程序仅使用可用内存的一小部分。如果代码段重复 50,000 次,并且仍然没有回收任何内存,那将是不同的结果。需要充分强调底层系统,使其被迫回收内存。
这可能是定义中最微妙但最重要的部分。在许多情况下,调用 destroy 或其他清理可能不会释放所有已分配的资源。在 Ext JS 中,这通常在其缓存中观察到。
例如,Ext.ComponentQuery 类用于根据字符串选择器搜索组件。在内部,此字符串选择器被转换为可以在候选组件上执行的函数。构造此函数成本很高,并且通常,相同的查询会多次运行。由于这种重用,生成的函数保留在内存中。这里的关键点是缓存机制是有界的。
缓存是 LRU(最近最少使用)缓存。LRU 跟踪对集合中项目的访问。当访问项目时,它会被拉到前面。LRU 缓存也有最大大小。当添加项目超过最大大小时,最近最少使用的项目将从缓存中逐出。一旦达到最大限制,缓存就会规范化。这种性质的东西保留在内存中没有问题。只有当资源无限期地保留时,才会成为问题。
使用 Ext JS 的开发人员远离真正的内存管理。更糟糕的是,诸如 Window 任务管理器或 Mac 活动监视器之类的工具无法准确描述内存消耗。为了更好地理解因果关系有多远,评估内存管理层非常重要。
鉴于以上所述,很明显,JavaScript 开发人员对内存管理方面的大局几乎没有控制权。有很多活动部件,真正的内存管理只是一个小齿轮。
就本指南而言,我们将不再进一步讨论这些层。可以说,JavaScript 堆及其垃圾回收器执行他们认为合适的动作,并且不可能强迫它们以特定的方式运行。我们能做的最好的事情是确保引用未被用户代码或框架持有。
最终,使用常见的 OS 监视工具检查内存使用情况并观察到增长并不一定表示“内存泄漏”。
当应用程序未能清理框架资源时,这可能会导致对象在框架维护的多个集合中累积。虽然这些集合的确切细节是特定于版本的,但一些检查的地方是
虽然已尽一切努力清理框架内部的资源,但总有出错的余地。从历史上看,最常见的问题来自泄漏的 DOM 元素。
注意: 我们强烈建议您在查看较低级别的内容之前解决所有应用程序级别的泄漏。
以下代码片段和描述将突出显示可能导致问题的各种内存滥用方式。
为了清理派生类中的资源,可能会意外绕过基类清理。
例如
Ext.define('Foo.bar.CustomButton', {
extend: 'Ext.button.Button',
onDestroy: function () {
// do some cleanup
}
});
解决方案: 务必调用 callParent(),这允许基类执行其清理。
事件附加到元素。元素被更改 innerHTML 覆盖。但是,此事件处理程序将保留在内存中。
Ext.fly(someElement).on('click', doSomething);
someElement.parentNode.innerHTML = '';
解决方案: 保留对重要元素的引用,并在不再需要它们时调用其 destroy 方法。
创建了使用大量内存的类的实例。该类被销毁,但引用保留在现有对象上。
Ext.define('MyClass', {
constructor: function() {
this.foo = new SomeLargeObject();
},
destroy: function() {
this.foo.destroy();
}
});
this.o = new MyClass();
o.destroy();
// `this` still has a reference to `o` and `o` has a reference to `foo`.
解决方案: 将引用设置为 null 以确保可以回收内存。在这种情况下,在 destroy 中使用 this.foo = null
,并在调用 destroy 后使用 this.o = null
。
这种情况更微妙,但与上述情况非常相似。闭包持有对大型对象的引用,该对象在仍然引用闭包时无法回收。
function runAsync(val) {
var o = new SomeLargeObject();
var x = 42;
// other things
return function() {
return x; // o is in closure scope but not needed
}
}
var f = runAsync(1);
上述情况经常发生,因为大型对象存在于外部作用域中,并且内部函数不需要它。这些事情很容易被忽略,但会对内存使用产生负面影响。
解决方案: 使用 Ext.Function.bind() 或标准 JavaScript Function bind
为在此类函数外部声明的函数创建安全闭包。
function fn (x) {
return x;
}
function runAsync(val) {
var o = new SomeLargeObject();
var x = 42;
// other things
return Ext.Function.bind(fn, null, [x]); // o is not captured
}
var f = runAsync(1);
创建某些对象可能会产生副作用(例如,创建 DOM 元素)。如果创建这些对象而没有销毁它们,则它们可能会泄漏内存。
{
xtype: 'treepanel',
listeners: {
itemclick: function(view, record, item, index, e) {
// Always creating and rendering a new menu
new Ext.menu.Menu({
items: [record.get('name')]
}).showAt(e.getXY());
}
}
}
解决方案: 捕获对菜单的引用,并在不再需要它时在其上调用 destroy 方法。
删除对对象的所有引用非常重要。将本地引用设置为 null 是不够的。如果某些全局单例缓存正在持有引用,则该引用将在应用程序的生命周期内被持有。
var o = new SomeLargeObject();
someCache.register(o);
// Destroy and null the reference. someCache still has a reference
o.destroy();
o = null;
解决方案: 除了调用 destroy 之外,还要确保从已添加对象的任何缓存中删除对象。
掌控应用程序的内存管理可以是一项简单的任务。通过销毁未使用的组件、使未使用的引用无效以及使用 callParent(),使您的应用程序无可指摘。遵循这些建议将确保您的应用程序平稳运行,并且不会不负责任地使用资源。