是什么让你的ExtJS应用程序运行缓慢?

 

本文说的“缓慢”,是只运行时 的缓慢,而不是只加载资源的时间。

在过去的一年半以来,我一直与Robert Bosch在Bosch软件创新公司工作,在那里我们的前端技术堆栈非常依赖ExtJS。我有机会开发Visual Rules Web Modeler机器协助开发其它几个基于ExtJS的应用,因此,我积累了不少与ExtJS应用常见的性能问题有关的经验。

在这篇文章中,我将与你们分享导致ExtJS应用运行缓慢的瓶颈问题,并指出ExtJS开发者最容易犯的错误。

本文提及的ExtJS是指版本3.3.x及以下版本的ExtJS。

1、过度的Ext.Panel定义

在我看来,最常用的ExtJS组件是Ext.Panel。在ExtJS里定义一个面板太简单了,因而很多开发人员很容易就会过度的定义它。下面是一个典型的嵌套了子面板的面板定义:

 

Java代码
  1. var   panel   =   new   Ext . Panel ( {                   //   Level-1  
  2.           title :   ' Multi   Column ,   Nested   Layouts   and   Anchoring ' ,   
  3.           bodyStyle : ' padding : 5px   5px   0 ' ,   
  4.           width :   600 ,   
  5.           items :   [ {                                       //   Level-2  
  6.                 layout : ' column ' ,   
  7.                 items : [ {                                 //   Level-3  
  8.                               columnWidth : . 5 ,   
  9.                               layout :   ' vbox ' ,   
  10.                               items :   [ {                       //   Level-4  
  11.                                     html :   ' This   is   some   text '  
  12.                               } ,   {   
  13.                                     html :   ' This   is   another   text '  
  14.                               } ]   
  15.                 } , {   
  16.                              columnWidth : . 5 ,   
  17.                              layout :   ' form ' ,   
  18.                               items :   [ {   
  19.                                             xtype : ' textfield ' ,   
  20.                                             fieldLabel :   ' Last   Name ' ,   
  21.                                             name :   ' last ' ,   
  22.                                             anchor : ' 95 % '  
  23.                               } , {   
  24.                                             xtype : ' textfield ' ,   
  25.                                            fieldLabel :   ' Email ' ,   
  26.                                             name :   ' email ' ,   
  27.                                             vtype : ' email ' ,   
  28.                                             anchor : ' 95 % '  
  29.                               } ]   
  30.               } ]   
  31.       } ]   
  32. } ) ;  
var   panel   =   new   Ext . Panel ( {                   //   Level-1
          title :   ' Multi   Column ,   Nested   Layouts   and   Anchoring ' ,
          bodyStyle : ' padding : 5px   5px   0 ' ,
          width :   600 ,
          items :   [ {                                       //   Level-2
                layout : ' column ' ,
                items : [ {                                 //   Level-3
                              columnWidth : . 5 ,
                              layout :   ' vbox ' ,
                              items :   [ {                       //   Level-4
                                    html :   ' This   is   some   text '
                              } ,   {
                                    html :   ' This   is   another   text '
                              } ]
                } , {
                             columnWidth : . 5 ,
                             layout :   ' form ' ,
                              items :   [ {
                                            xtype : ' textfield ' ,
                                            fieldLabel :   ' Last   Name ' ,
                                            name :   ' last ' ,
                                            anchor : ' 95 % '
                              } , {
                                            xtype : ' textfield ' ,
                                           fieldLabel :   ' Email ' ,
                                            name :   ' email ' ,
                                            vtype : ' email ' ,
                                            anchor : ' 95 % '
                              } ]
              } ]
      } ]
} ) ;

 

这定义有问题吗?没有?这里的主要问题是嵌套了4层面板,而实际上,只需要2层就可以工作了。

●这是一个过渡定义的例子,它导致了多层深度的嵌套的HTMLElement创建,以致严重影响了初始化时间、渲染时间和组件的运行时间。

●我见过很多ExtJS开发人员习惯定义嵌套面板,因为它这样可以方便在面板里加入自定义的样式、文本和图片等等,或者有时仅仅是因为显示需要,在里面添加其它的面板,

●经验法则是:用尽可能少的面板和尽可能的减少面板(组件)的嵌套。

要做到这一点,在定义一个复杂的组件时,必须明智地使用Ext的布局及其样式,

2、尽可能延迟HTMLElement的创建

DOM操作(读/写)的开销一向是昂贵的,尤其在IE6,读取DOM总会引起回滚。

因此,经验法则是:尽可能延迟HTMLElement的创建 。以下是实现方式:

●组件Lazy初始化,这在xtype里可实现。

●尝试在渲染后(afterrender)后再执行昂贵的操作。

●避免在组件的构造函数或initComponent方法中对其它组件进行不必要的实例化或渲染。

例子1:1个简单的例子就是在按钮第一次渲染时,不创建Ext.Tooltio或在一个隐藏的DOM节点渲染它。tooltip通常会在用户第一次将鼠标移动到按钮上面时进行渲染。如果tooltip在按钮之后显示,用户就不必将鼠标移动到按钮上了。其实这是一种浪费,永远不要做这样的事,使用tooltip只会增加性能问题。

 

示例2:另一个例子是粗心的使用renderTo:

Java代码
  1. var   window   =   new   Ext . Window ( {   
  2.           renderTo :   document . body ,   
  3.           title :   ' The   Untitled '  
  4. } ) ;   
  5.     
  6. window . show ( ) ;   //   窗口将会在这之前渲染  
var   window   =   new   Ext . Window ( {
          renderTo :   document . body ,
          title :   ' The   Untitled '
} ) ;
 
window . show ( ) ;   //   窗口将会在这之前渲染
  

上述定义,窗口将会立即渲染和隐藏在body标记内。在大多数情况下,窗口根本不需要使用renderTo,因为它会在第一次显示时进行渲染:

Java代码
  1. var   window   =   new   Ext . Window ( {   
  2.                   title :   ' The   Untitled '  
  3.     } ) ;   
  4.         
  5.     window . show ( ) ;   //   窗口会在这时候进行渲染  
var   window   =   new   Ext . Window ( {
	              title :   ' The   Untitled '
	} ) ;
	 
	window . show ( ) ;   //   窗口会在这时候进行渲染
  

3、尽可能使用委托模式

我不会在这里深入挖掘委托模式的细节,但会在ExtJS语法基础上重组它。

示例:一个委托模式的示例是工具条有10个按钮,而你希望在用户将鼠标移动到按钮上面时,为每个按钮委派一个Ext.Tooltip,而且每个Ext.Tooltip都显示不同的文本。

如果你创建10个Ext.Tooltip并委派给10个按钮,那么它不是一个优化的解决方案。你只需要创建一个Ext.Tooltip并委派给10个按钮的父元素,也就是工具条。

当用户将鼠标移动到工具条上方时,你可以显示相同的Ext.Tooltip,但其文本可根据目标元素(实际上就是按钮)而显示不同的文本(越多getTarget方法可了解如何获取目标元素)。

使用这个技术,只需要创建1个Ext.Tooltip,而且只需要在工具条绑定一个监听事件。

这可节省内存使用,而且在你的应用运行时实现了相同的效果。

你可以在这里 找到示例中Ext.Tooltip的delegate属性信息。

4、组件销毁——如何正确销毁

在我协助提供性能期间,我发现ExtJS应用缓慢的一个主要瓶颈就是组件的销毁。这里所说的组件销毁是指不再使用的组件,我们应该清理:

●DOM中的HTMLElement。

●移除所有监听事件以避免内存泄漏。

●通过递归方式销毁所有子组件。

以上这些可通过组件的destory方法来处理。有些时候,在运行时,使用destroy方法移除不使用的组件,会导致严重的性能下降。

示例1:如果你在一个面板内创建了一个弹出菜单,记得重写面板的destroy方法,在里面添加销毁弹出菜单的代码。这样,当面板被销毁时,弹出菜单也会被销毁。

Java代码
  1. Your . Component . Klass   =   Ext . extend ( Ext . Component ,   {   
  2.     initComponent :   function ( ) {   
  3.               //   Initialize   your   custom   stuff  
  4.               this . contextMenu   =   new   Ext . menu . Menu ( {   
  5.                           renderTo :   document . body   
  6.                           //   ..  
  7.                 } ) ;   
  8.     } ,   
  9.         
  10.     destroy :   function ( ) {   
  11.                 //   Destroy   your   custom   stuff  
  12.                 this . contextMenu . destroy ( ) ;   
  13.                 this . contextMenu   =   null ;   
  14.         
  15.                 //   Destroy   the   component  
  16.                 Your . Component . Klass . superclass . destroy . call ( this ) ;   
  17.     }   
  18.     } ) ;  
Your . Component . Klass   =   Ext . extend ( Ext . Component ,   {
 	initComponent :   function ( ) {
 	          //   Initialize   your   custom   stuff
 	          this . contextMenu   =   new   Ext . menu . Menu ( {
 	                      renderTo :   document . body
 	                      //   ..
 	            } ) ;
 	} ,
 	 
 	destroy :   function ( ) {
 	            //   Destroy   your   custom   stuff
 	            this . contextMenu . destroy ( ) ;
 	            this . contextMenu   =   null ;
 	 
 	            //   Destroy   the   component
 	            Your . Component . Klass . superclass . destroy . call ( this ) ;
 	}
 	} ) ;
 
示例2:大家都会犯的错误就是错误定义窗口的closeAction配置项。

如果配置closeAction为hide,那么当用户单击关闭按钮关闭窗口时,窗口将变成不可见。然而,有时候,窗口在整个运行期间,都不会再显示第二次。因而,你必须确保窗口是需要隐藏或显示的,不然就配置closeAction为close,以便在窗口被关闭时执行destroy方法以销毁窗口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值