Ext JS - 高效的編碼風格指南

1,切勿使用“new”關鍵字:在Ext JS中,使用“new”關鍵字來創建一個組件或類的實例是一種錯誤的做法,因爲這沒有遵循組件的生命週期。應該使用Ext.create方法來創建對象,例如:

1.錯誤: var obj = new Ext.panel.Panel();
2. 
3.正確: var obj = Ext.create(‘Ext.panel.Panel’);

2,初始化直接量:不要直接創建直接量的對象,例如,使用以下javascript來創建空白對象:

1.var stringObj = new String();
2.var arrayObj = new Array();
3.var obj = new Object();

在javascript中,以上都是創建對象的不正確方式,這是因爲如果使用這些處理方式,控制需要去遍歷整個類的層次。因此,作爲替代,可以使用以下方式來創建這些類的對象:


1.var stringObj = ‘’;
2.var arrayObj = [];
3.var obj = {};

不過,你接手的可能是別人編寫的遺留代碼,因而會注意到構造函數的一個“特色”(這或者是另一個不使用它的理由)。“特色”的主要問題是Object的構造函數可接受參數,並且它會根據傳入的值來決定是否將對象的創建委託給另一個內置構造函數,而最終返回的對象可能不是你所預期的,例如:


1.// Warning: antipatterns ahead
2.// an empty object
3.var o = new Object();
4.console.log(o.constructor === Object); // true
5.// a number object
6.var o = new Object(1);
7.console.log(o.constructor === Number); // true

3,更聰明的使用getCmp:它將根據傳遞的id值返回匹配的對象(Ext JS對象)。這是一種快速返回對象的方法。所有對象在創建的時候,都需要使用他們的id作爲關鍵字註冊爲一個單一對象,這樣,使用Ext.getCmp(myId)就可以尋找並返回RegistrationObject["myId"],因此,這會變得非常快捷。

不過,如果都個組件使用了相同的id,它就會失效。在這種情況下,它將會返回最後一個查找到的對象。基於這點,建議儘量不要使用這個來獲取對象。建議的做法是隻使用該方法一次,然後將結果保存到一個變量,再在其他地方通過變量來引用對象。

如果需要爲多個組件定義相同的id,建議使用itemId。通過這篇文章可瞭解id和itemId直接的不同。

4,避免不比亞的全局變量:使用全局變量的主要問題就是它可在javascript應用程序或Web頁面中共享所有代碼。這可能會與使用相同名稱的命名空間引起衝突,在應用程序的兩個單獨部分定義具有相同名稱但用途不同的全局變量的可能性是存在的。使用不必要的全局變量的第二個缺點是會造成更大的內存損耗,這是因爲,對於這些全局變量,一般情況下是不會進行垃圾回收的,因而不會釋放內存。

5,使用var關鍵字來定義全局變量:使用var來定義全局變量與不使用之間的一個細微差別是:能不能使用delete操作符來刪除這些變量。
使用var來定義的全局變量(包括在函數內創建的)不能使用delete來刪除,例如:


01.// define three globals
02.var global_var = 1;
03.global_novar = 2; // antipattern
04.(function () {
05.global_fromfunc = 3; // antipattern
06.}());
07.// attempt to delete
08.delete global_var; // false
09.delete global_novar; // true
10.delete global_fromfunc; // true
11.// test the deletion
12.typeof global_var; // "number"
13.typeof global_novar; // "undefined"
14.typeof global_fromfunc; // "undefined"

6,嘗試去刪除那些未使用的變量和函數:不要保留代碼中那些沒有使用到的變量、函數或者不必要的註釋,因爲這些只會增加文件的大小,從而增加文件的加載時間。

7,避免在循環中創建對象或變量:如果沒有必要,就不要在循環中創建單一的變量或對象,因爲他們的數量會隨着選好的迭代次數而增加,進而造成內存泄漏。

8,避免過度使用面板:在大多數情況下,Ext JS應用程序會受到面板過度使用的影響。無論什麼情況都使用面板,或者更準確的說,是無論任何情況下都會使用多個面板。解決辦法就是在使用一些輕量級的替代品來代替面板。很多人都喜歡面板,不過說實在,在UI的許多部分有點過分了。我曾經看到一個用來顯示幾十個縮略圖的UI,每個圖像都是使用不同面板的HTML內容來顯示的,而這些面板是完全沒必要的。可以考慮以下替代方法……

  • 是否可使用HTML和CSS,而不是完整的組件?使用Ext.Template或Ext.XTemplate可能更實際。
  • 是否可以使用自定義的Ext.Component?可以使用不同的配置項來將HTML豬肉到組件:autoEl、html、tpl或數據。
  • 是否可以使用數據視圖(DataView)來渲染所有數據而不是單獨的組件?
  • 是否可以使用Ext.container.Container,而不是Ext.panel.Panel來減少開銷?

9,避免容器嵌套:儘量避免不必要地使用容器,因爲每個容器都會創建一個層次結構,並以此爲核心來訪問子組件,而這,需要遍歷這些容器的層次結構。因此,要儘量在最小的可能容器數量下創建視圖。

10,函數要儘可能小:每一個函數都應短小精幹和有意義。大的函數會降低可讀性、可維護性、可重用性和可調試性。除此之外,如果一個對象(非常消耗內存的對象)在函數開始時進行實例化,它就會一直存在到函數結束。所以,如果函數非常小,那麼,它的局部變量、對象等垃圾就可以在更短的時間跨度內被回收,從而釋放內存於其他用途。

11,儘量避免過長的對象引用:應儘量避免大型對象的引用,因爲這需要花費更多的時間來遍歷對象的層次結構來獲取所需的組件,例如:


1.var arrayLength = arrayObj.lenght;
2.for( var I = 0; I < arrayLenght; i++){
3.//anti pattern
4.If(Abc.xyz.foo.bar.againFoo.againBar.finalObj === arrayObj[i]){
5.Alert(‘Anti pattern code’);
6.}
7.}

以上代碼可重寫爲以下更有效的方式:

1.var arrayLength = arrayObj.lenght;
2.var obj = Abc.xyz.foo.bar.againFoo.againBar.finalObj;
3.for( var I = 0; I < arrayLenght; i++){
4.//pattern
5.If(obj === arrayObj[i]){
6.Alert(‘pattern code’);
7.}
8.}

12,應避免吊裝(hoisting)問題:javascript允許在一個函數內任何個地方使用多個var語句,而他們的行爲與在函數頂部定義變量是沒有區別的,這種行爲通常被稱爲吊裝。在使用變量之後再在函數內進行聲明,可能會導致邏輯錯誤。對於javascript來說,只要變量在同一作用域(同一函數)被使用,它就會被聲明,無論是否使用了var來定義,例如:


1.// antipattern
2.myname = "global"; // global variable
3.function func() {
4.alert(myname); // "undefined"
5.var myname = "local";
6.alert(myname); // "local"
7.}
8.func();

第一個alert將會顯示“underfined”,這是因爲myname被認爲是在函數內部的局部變量(儘管是在之後聲明的)。所以變量的定義都會被吊裝到函數頂部。因此,要避免這種混亂,最好的方式就是在前期聲明所有打算使用到的變量。

13,創建高效的for循環:使用for循環來遍歷javascript集合,應將集合的長度緩存到一個變量,並使用改變量作爲for循環的條件,例如:


01.for (var i = 0; i < myarray.length; i++) { //antipattern use of collection length
02.// do something with myarray
03.}
04. 
05.//Right pattern
06.var arrLength =  myarray.length;
07.for (var i = 0; i < arrLength; i++) {
08.// do something with myarray
09.}

14,使用hasOwnProperty:在遍歷對象的屬性的時候,使用hasOwnProperty方法來過濾原型鏈屬性是相當重要的,例如:


1.var man = {hands: 2, legs: 2, head: 1};
2.//somewhere else in the code
3.// a method was added to all object
4.If( typeof Object.prototype.clone === undefined){
5.Object.prototype.clone = function(){};
6.}

在定義了man之前,對象原型添加了一個有用的名爲clone的方法。原型鏈的存在意味着所以對象都會自動獲得該新方法。爲了避免在枚舉man的時候顯示clone方法,就需要調用hasOwnProperty方法來過濾原型方法,例如:


01.// 1.
02.// for-in loop
03.for (var i in man) {
04.if (man.hasOwnProperty(i)) { // filter
05.console.log(i, ":", man[i]);
06.}
07.}
08./*
09.result in the console
10.hands : 2, legs : 2, heads : 1
11.*/
12.// 2.
13.// antipattern:
14.// for-in loop without checking hasOwnProperty()
15.for (var i in man) {
16.console.log(i, ":", man[i]);
17.}
18./*
19.result in the console
20.hands : 2, legs : 2, heads : 1, clone: function()
21.*/

15,使用===代替==:javascript在比較隱式類型變量的時候,會進行類型轉換,而這也就是爲什麼在比較“false== 0”或“"" == 0”時返回true的原因。爲了避免因隱式類型轉換所造成的混亂,在比對值與不同的類型表達式的時候,應始終使用===或!==操作符來進行檢查。


1.var zero = 0;
2.if (zero === false) {
3.// not executing because zero is 0, not false
4.}
5.// antipattern
6.if (zero == false) {
7.// this block is executed...
8.}

另一學派的觀點是,當使用==已經足矣的時候,使用===就顯得有掉多餘,例如,當使用typeof的時候,明確返回的是字符串,這時候就沒必要使用恆等。不過JSLint要求嚴格的相等,它要求代碼保持一致的外觀以及減少閱讀代碼的精力(這個==是故意還是遺漏?)。

16,不要使用eval:一定要記住“eval是魔鬼”這句口頭禪。這個函數可接受任意的字符串,並將字符串作爲javascript代碼執行,例如:


1.console.log(typeof un); // "undefined"
2.var jsstring = "var un = 1; console.log(un);";
3.eval(jsstring); // logs "1"
4.console.log(typeof un); // "number"

因此,在這裏使用eval會將un定義爲一個數字直接量。假如把jsstrig的值作爲用戶的輸入值,這將會導致不少的安全問題。所以,使用eval會帶來安全隱患。

17,parseInt的正確用法:正確使用parseInt的redix可以避免一些不必要的結果,例如:


1.alert(parseInt("8")); // "Will print 8"
2.alert(parseInt("08")); // "Will print 0"
3.alert(parseInt("08,10")); // "Will print 8"
4.If we use parseInt(“08”), it gives octal value of 08.

因此,要永遠記住使用第二個變量,即redix,來定義數字的類型,無論它是十進制、八進制還是十六進制。

18,小心函數吊裝:該問題類似於上面討論的變量吊裝。他們唯一的區別是隻在使用函數聲明纔會發生,而不是匿名函數。函數聲明這種情況,函數聲明被吊裝時,不單只是聲明問題,處理不當就會出現一些非預想的結果,例如:


01.// antipattern
02.// for illustration only
03.// global functions
04.function foo() {
05.alert('global foo');
06.}
07.function bar() {
08.alert('global bar');
09.}
10.function hoistMe() {
11.console.log(typeof foo); // "function"
12.console.log(typeof bar); // "undefined"
13.foo(); // "local foo"
14.bar(); // TypeError: bar is not a function
15.// function declaration:
16.// variable 'foo' and its implementation both get hoisted
17.function foo() {
18.alert('local foo');
19.}
20.// function expression:
21.// only variable 'bar' gets hoisted
22.// not the implementation
23.var bar = function () {
24.alert('local bar');
25.};
26.}
27.hoistMe();

在示例中,會看到就像普通變量一樣,無論foo或bar自身位於hoistMe的任何地方,都會將他們移動到頂部,重寫全局的foo和bar。不同的地方是本地(local)的foo定義被吊裝到頂部並能正常工作,儘管它是在後面定義的。而bar的定義則不會被吊裝,只是進行了聲明。這就是爲什麼直到代碼執行到bar的定義,會發現它是undefined且不能作爲函數使用(同時阻止了全局的bar出現在作用域鏈中)。

19,將屬性添加到全局命名空間:在將一個屬性添加到全局命名空間或全局對象的時候,要小心,或許這已經存在了,可能會覆蓋掉他們。因此,在添加一個屬性或創建命名空間之前,最好先檢查一下它是否存在,例如:


1.// unsafe and antipattern
2.var MYAPP = {};
3.// better
4.if (typeof MYAPP === "undefined") {
5.var MYAPP = {};
6.}
7.// or shorter
8.var MYAPP = MYAPP || {};

爲了避免在全局命名空間創建任何成員時編寫這些樣板代碼,可以創建一些可重用的代碼,將要創建的對象傳遞過去,讓代碼去執行上述驗證並決定添加或放棄對象。

20,利用JSLint:JSLint會獲取javascript源代碼並掃描他們。如果發現問題,它會返回問題描述和大致位置的消息。問題不一定是語法錯誤,儘管經常會是。JSLint專注於一些風格約定和結構問題。這並不能說明你的程序是正確,只是提供一些方式來協助發現問題。只需要簡單的粘貼腳本,它就可以快速的掃描代碼並找出任何明顯的問題和錯誤。

21,避免使用with語句:乍看上去,With語句看上去不賴,主要原因是它可以提供一種簡單方式來訪問嵌套很深的對象,例如:


1.with (being.person.man.bodyparts) { 
2.arms = true
3.legs = true
4.}

代替:


1.being.person.man.bodyparts.arms = true
2.being.person.man.bodyparts.legs= true;

不幸的是,經過一些測試後,會發現他們在設置新成員時的表現非常糟糕,替代方法是,可以使用var:


1.var o = being.person.man.bodyparts; 
2.o.arms = true
3.o.legs = true;

22,使用Ext JS內部函數來添加或移除Ext JS組件的元素:要將一些對象添加到Ext JS容易,不建議使用以下代碼:


1.componentObj.items.items[0] = newObject;

以上代碼的問題:如果使用以上代碼將一些東西添加到容易,Ext JS的所有內部任務就不會在將對象添加到容器時執行,而這將會引起一些問題。

解決:應使用容器的add方法,或使用組件其他類似的內部函數來處理。

23,從Ext JS的組件中返回組件:要從Ext JS的組件中返回對象,不要使用以下代碼:

1.var anObj = componentObject.items.items[0].items.items[1];

問題:如果在上述層次結構加入了一個新的層,如一個面板或容器,那麼整個層次結構就會變得不穩定,可能會返回錯誤的結果。

解決:使用Ext.getCmp或queryById來代替過長的層級遍歷。儘管這比層級遍歷要慢,但可保證不會出現以上所說層次問題。

(譯者注:在4中,可使用down或up方法查詢子組件或父組件)

24,編寫可讀、可調試和可重用的代碼:在編寫代碼時,開發人員應創建短小且有意義的類或函數。不要試圖去把大量的代碼寫在一個單獨的塊中。儘量保持代碼塊短小,從而讓它跟易於重複使用,且更易於閱讀。

25,使用get/set方法:如果使用config配置項來定義類的變量,Ext JS會自動創建變量的修改方法(setter)和訪問方法(getter),使用這些修改方法和訪問方法可提供代碼的可讀性。如果使用這些方法來而不是直接使用變量名,還可以重寫這些方法或爲這些方法添加功能。因此,應儘可能使用訪問方法和修改方法作爲類這層的變量並使用他們。

26,永遠不要使用自動佈局來創建組件:一些常見的錯誤就是因爲Ext JS開發人員在創建容器的時候忘記爲他們定義佈局了。儘管這在一些瀏覽器上或特定版本的瀏覽器會運行得很好,但從長遠來看,這會導致某些部件出現黑屏或失真等問題,例如:


01.Ext.create(‘Ext.panel.Panel’,{
02.height: 200,
03.width: 500,
04.//layout: ‘hbox’,          // anti pattern if layout is not defined
05.items:[
06.{
07.xtype: ‘button’,
08.id: ‘button1’
09.flex: 1
10.},{
11.xtype: ‘button’,
12.id: ‘button2’
13.flex: 1
14.}
15.]
16.});

在這裏,在面板中沒有定義佈局,面板的高度和寬度將不會根據它的組件的flex值進行分配。原因就是容器的佈局不知道如何將容器的高度和寬度分配給容器的組件。如果把“layout:hbox”的註釋去掉,這兩個按鈕將會根據父容器調整寬帶和高度。

27,避免使用固定的高度和寬度:千萬不要在應用程序中固定任何容器或組件的高度和寬度,因爲這會破壞應用程序的佈局流動性。儘量將最頂層的容器或viewport的高度和寬度定義爲屏幕大小,然後小心的通過正確的使用flex或佈局將這個尺寸分分派給子組件或子容器,不要使用硬編碼的高度或寬度,也可以通過使用Ext JS的功能來計算,如Ext.getBody().getViewSize().height或Ext..getBody().width:


1.Ext.create(“Ext.panel.Panel”,{
2.height: Ext.getBody().getViewSize().height,
3.width: Ext.getBody().getViewSize().width
4.});

28,正確使用flex關鍵字:flex是一個用來保持流動性佈局的非常重要的關鍵字,該值通常用來決定如何接收父容器的尺寸,例如,如果兩個組件的定義分別爲flex=1和flex=2,那麼,這兩個組件從父容器接收到的尺寸比例就是1:2。在這裏,還需要留意另一個重點,就是該值只用來劃分父容器的寬度或高度,而不能同時來決定子組件的寬度和高度,例如:


01.Ext.create(‘Ext.panel.Panel’,{
02.height: 200,
03.width: 500,
04.layout: ‘hbox’,        
05.items:[
06.{
07.xtype: ‘button’,
08.id: ‘button1’
09.flex: 1
10.},{
11.xtype: ‘button’,
12.id: ‘button2’
13.flex: 1
14.}
15.]
16.});

以上代碼,使用了水平盒子佈局,因而,只有按鈕的寬度會根據flex值的比例進行劃分,而兩個按鈕的高度則會是100%,即是每個按鈕的寬度會是250,而高度是200。同樣,如果將面板的佈局修改爲垂直盒子佈局,那麼,每一個按鈕的寬度將會是500,而高度會是100。因此,要適當並謹慎地使用flex來實現更好的流動佈局。

29,儘量少用minxWidth、maxWidth、minHeight和maxHeight:儘量在需要的時候才使用這些屬性,否則就不要使用他們,因爲在組件佈局方面,他們的使用是非常昂貴的。如果在組件中碰到這些屬性,佈局會重新進行計算,因此,這樣的代價非常昂貴。

30,使用Sencha Cmd工具來壓縮(minification)代碼:進行壓縮處理時,會消除空白、註釋和javascript代碼中其他不重要的部分,這樣可減少javascript文件的大小,從而減小服務器到瀏覽器的傳輸量。另外,壓縮處理還會重命名變量爲較短的名稱(但只有在它是安全的時候),如前面代碼中的參數D、C、B或A。壓縮處理只會重命名局部變量,因爲重命名全局變量可能破壞代碼。這也是爲什麼使用局部變量是一個好做法的主要願意。如果在一個函數內,使用全局變量,如DOM引用,超過一到兩次,那就給它分配一個局部變量,這是好的做法。這些通常需要一些工具(壓縮)來實現,如Ext JS命令行工具(只適用於Ext JS的應用程序開發)、雅虎的YUICompressor或谷歌的Closure Complier(適用於普通的javascript應用程序),這喲這樣加快頁面加載時間。壓縮爲生產準備的腳本是十分重要的,因爲最終可以將文件的大小大大壓縮,通常可以壓縮一半的大小。

31,保持DOM的輕量化:儘量保持DOM的輕量化可加快DOM的訪問和維護速度。這可通過移除不必要的DOM元素來實現,例如,如果使用卡片佈局,且每個卡片都要顯示大量容器或組件,而且用戶不會返回之前的卡片,最好的方式就是在程序(這樣所需的容器或組件就不會再次創建)中緩存DOM元素,然後將DOM
元素從DOM中移除以讓它輕量化。

32,儘量減少DOM訪問:DOM訪問是昂貴的,它是javascript性能最常見的瓶頸。這是因爲DOM的實現通常是與javascript引擎分離的。底線就是應將DOM訪問減少到最低限度,這意味着:

  • 避免在循環中進行DOM訪問
  • 將DOM引用指派給局部變量並使用舉報變量進行操作
  • 在可能的情況下,使用API的選擇器
  • 當要遍歷HTML集合時,緩存集合的長度
  • 儘量使用Ext JS的方法來訪問或維護DOM,以獲得跨瀏覽器支持,否則某些代碼在某些瀏覽器可能會失敗,這是因爲每個瀏覽器都有它自己的DOM訪問方式。

33,不要創建內聯處理函數:千萬必要創建內聯函數,因爲對於回調會監聽所使用的函數來說,是常見的問題源。他們不單需要花費時間來創建,還需要昂貴的閉包,例如:


1.Ext.define(‘MyClass’,{
2.constructor: function(config){
3.this.store.on(‘load’, function(){
4.………..;
5.}, this);
6.}
7.});

以上代碼,每當構造函數執行一次,就會創建一個新的監聽函數,這不單需要花費時間處理閉包問題,還潛在內存泄漏問題。以下是首選的模式:

1.Ext.define(‘MyClass’,{
2.constructor: function(config){
3.this.store.on(‘load’, this.onStoreLoad, this);
4.},
5.onStoreLoad: function(){
6.………;
7.}
8.});

在以上代碼中,監聽函數只會創建一次並保存在類中。每個實例都會共享相同的函數。創建函數的開銷只有一次,而且沒有閉包泄漏的風險。更重要的是,這樣的編碼風格,還可以讓子類輕鬆的去重寫監聽。

34,正確使用xtype:一個常見的神話就是xtype可通過延遲初始化提高性能。通常,這不是真的。儘管通過xtype配置項將組件添加到容器,它還是進行實例化,儘管它還不可見。雖然xtype有很大用途,但對於應用程序的性能或資源消耗來說沒有實際可衡量的影響。

35,千萬不要使用整個ext-all.js庫:通常,ext-all.js是包含了全部功能和組件的巨大編碼集,但我們很少會使用到Ext JS的全部功能和組件,因此,沒必要在只使用了60%到70%代碼的時候去加載一個巨大的文件。可以使用Sencha命令行工具來壓縮生產代碼,它會從ext-all.js中複製所需的類並粘貼到結果all-classes.js。如果沒有使用Sencha命令行工具,還可以通過其他方式來確保不用加載整4個ext-all.js文件。

36,批處理任務:儘量使用批處理進行更新,以便渲染只在最後時刻觸發一次渲染。例如,修改記錄的字段值會立即更新到網格,如果想讓幾個字段的更新更高效,就進行批處理,例如:

1.record.beginEdit();
2.record.set(‘name’, ‘Tom’);
3.record.set(‘age’, 17);
4.record.set(‘member’, true);
5.record.endEdit();

如果要修改的字段更多,效果會更明顯。
另一個例子是將組件添加到容器,每添加一次,容器就會重新計算佈局一次。將多個組件傳遞給同一個add方法,將會高效得多,例如:


01.//slow code
02.container.add(panel);
03.container.add(button);
04.container.add(grid);
05. 
06.//fast
07.container.add(panel, button, grid);
08. 
09.//using an array is also fast
10.container.add([panel, button, grid]);

在沒有其他批處理機制的時候,可以使用暫停佈局來臨時輔助實現:

1.container.suspendLayout = true;
2.doSomethingToChangeLotsOfLayoutChange();
3.container.suspendLayout = false;
4.container.doLayout();

37,使用deferredRender:在使用卡片佈局或標籤面板的時候,要認真考慮一下deferredRender選項。當將它設置爲true,就可以將隱藏的條目或選項卡實現延遲渲染。只有在隱藏的條目第一次顯示的時候,纔會進行渲染。當設置爲false,所以的卡片或標籤就會作爲容器渲染的一部分在同一時間進行渲染。
延遲渲染通常來說挺好的,這有助於將渲染過程分解爲較小的數據塊,不會對用戶造成明顯的延遲。不過,渲染所有的卡片或標籤頁,在隱藏的卡片或標籤頁第一次顯示的時候有助於改善UI的響應。

38,網格的緩衝渲染:在使用網格的時候,如果數據集很打,使用緩衝渲染吧。這意味着在加載存儲的時候,存儲要維持一個“預讀”緩衝,以保存將要使用到的記錄頁。
如果數據少於100000行(也取決於每行的列數),最好的方式是在客戶端將所有數據保存到預讀緩衝區。
渲染大的HTML表格會謀殺性能。這事實上只是HTML表格算法,只保持所以數據應該不會導致問題。
要做的只是滾動的時候,在“適當時候”渲染表格的行。要做到這一點,只需要一次加載預讀緩衝中的所有數據。這樣做後,就可以從預讀緩存中加載存儲的主要數據,例如:


01.myStore = ……{
02.………….,
03.Buffered: true, // Tell grid to use a paging scroll manager to scroll and refresh table automatically.
04.perPageCount: 0 // never remove pages from the prefetch buffer;
05.}
06. 
07.myStore.prefetch({
08.start: 0,
09.limit: 999999,
10.callback: function(){
11.myStore.load(0, 49);
12.}
13.});

預讀所有所預期的數據集後,回調會加載存儲的主緩存(映射到網格面板內的緩存)所使用的50行數據。由於只能得到小於50行的表格,所以在滾動接近視圖邊界的時候,它就會更新。該技術在4.0.x工作OK,不過在4.1.0進行了翻修,變得更快和更平滑。在網格目錄的緩衝網格示例延時該技術。
要注意的是,太多的列會對HTML的性能產生影響。
元素太多也會這樣,因而需要避免顯示不需要的列。

39,在標籤面板的每個標籤頁的beforeRender事件處理中填充標籤頁:在beforeRendere中填充標籤頁是更好的方法。正確的實現這個可以有效的改進包含大量未渲染組件的應用程序的性能。雖然實例化一個組件的時間比渲染或佈局所需要的時間要小,但如果有大量的未渲染組件也需要時間。帶有許多標籤頁的標籤面板這樣處理會更理想。要特別支出的是,我建議的只是shuffle time around:cut the time taken for the initial load in favour of slightly slower tab transitions.這只是你武器庫中的另一種技術。與以往一樣,優化的黃金規則是在實現之前,要做一些有意義的測量。

40,使用mon代替on:這兩個關鍵字都是用來事件處理綁定到事件的。不過,使用mon而不是on會更高效,因爲這可確保監聽會在MyClass的實例被銷燬的時候自動移除它,例如:


01.Ext.define(‘MyClass’,{
02.Constructor: function(config){
03.//this.store.on(‘load’, this.onStoreLoad, this); // this is not good
04.this.store.mon(‘load’, this.onStoreLoad, this);
05.},
06.onStoreLoad: function(){
07.………;
08.}
09. 
10.});

41,在事件處理程序中不要保留對this的引用:通常,在任何Ext JS組件的內聯事件處理函數工作時,都需要使用this關鍵字來獲取相應類的對象的應用。通常情況下,組件的事件處理程序的this指向的是該組件這個對象。隱藏,要解決這個問題,一些開發人員會在構造函數或類的initComponent方法內使用一些全局變量來引用類,然後在內聯處理中使用全局變量來獲取相應的類對象,不過,這是錯誤的做法,我們贏遵循這裏的約定。

42,嘗試使用客戶端緩存:本地存儲、session存儲、sqllite等等。如果使用HTML5,就可以將一些數據保持在客戶端(不是cookie),並在再次瀏覽該頁時使用這些數據。這樣,就可以避免將一些沒必要的東西發送到服務器或數據庫。在Ext JS,可以使用代理來處理這類緩存。在Ext JS中有兩類代理:ClientProxy和ServerProxy。ClientProxy就是用來處理客戶端緩存的。有以下三種類型的ClientProxy:

  • Ext.data.proxy.LocalStorage:LocalStorageProxy使用新的HTML5的localStorage來加載和保存數據到客戶端瀏覽器。LocalStorage可在域中設置字段,這意味着關閉瀏覽器後再打開它,數據還在LocalStorage中。LocalStorage允許長期存儲,此外還可以在所有瀏覽器的標籤頁或窗口中訪問它。
  • Ext.data.proxy.SessionStorage:SessionStorageProxy使用的是新的HTML5的SessionStorage API來加載和保持數據到客戶端瀏覽器。SessionStorage設置的字段是基於窗口的,這意味着瀏覽器關閉後,數據也會丟失,即使網站在另一個瀏覽器窗口依然是打開的。SessionStorage的數據被侷限於創建他的瀏覽器窗口中。
  • Ext.data.proxy.MemoryProxy:MemoryProxy是一個輔助性的代理。通常,它用來加載一些內聯數據到存儲。MemoryProxy的內容會在頁面刷新後對視。它通常用來加載臨時數據。

除了這些,一些瀏覽器,如chrome,還支持一些特殊類型的客戶端數據,如SQLLite,它可以在客戶端存儲一些數據。因此,通過使用這些技術,可以用來提高應用程序的性能。

43,不要使用Array.isArray:Array.isArray(anyObject)方法用來判斷anyObject是否一個數組對象。該方法只能在Chrome中工作,不能在IE中工作。IE並不能識別該方法並會給出錯誤。可使用instanceof來替代該方法來達到相同的目的。instanceof方法既可在IE工作,也可在Chrome工作。

44,一定要注意日期格式:在解析日期的時候,要注意日期字符串的格式是否既支持IE,又支chrom:


1.var dateString = "03/20/2008";                                
2.var dateString = "2008/03/20";                                                
3.var dateString = "03-20-2008";                                 
4.var dateString = "March 20, 2008";                                        
5.var dateString = "Mar 20, 2008";                                             
6.var dateString = "Oct 2, 2011";

不要使用var dateString = "Oct/02/2011",IE不支持,在chrome中是支持的。我已經在應用程序修正了這個。

45,別忘了以下要點:以下是在將代碼發佈爲產品時不應忘記的一些要點:

  • 沒有尾隨逗號
  • 即使只有一行註釋,也要使用多行註釋來代替單行註釋
  • 沒有調試的代碼要留下注釋
  • 在預期的情況下,不要丟失任何分號
  • 不要在生產代碼中使用console.log
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章