原文:ExtJS - Efficient coding style guide
彭山ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!
作者:Raja
切勿使用“new”關(guān)鍵字:在Ext JS中,使用“new”關(guān)鍵字來創(chuàng)建一個(gè)組件或類的實(shí)例是一種錯(cuò)誤的做法,因?yàn)檫@沒有遵循組件的生命周期。應(yīng)該使用Ext.create方法來創(chuàng)建對(duì)象,例如:
[javascript]view plaincopy
錯(cuò)誤: var obj = new Ext.panel.Panel();
正確: var obj = Ext.create(‘Ext.panel.Panel’);
初始化直接量:不要直接創(chuàng)建直接量的對(duì)象,例如,使用以下javascript來創(chuàng)建空白對(duì)象:
[javascript]view plaincopy
在javascript中,以上都是創(chuàng)建對(duì)象的不正確方式,這是因?yàn)槿绻褂眠@些處理方式,控制需要去遍歷整個(gè)類的層次。因此,作為替代,可以使用以下方式來創(chuàng)建這些類的對(duì)象:
[javascript]view plaincopy
不
過,你接手的可能是別人編寫的遺留代碼,因而會(huì)注意到構(gòu)造函數(shù)的一個(gè)“特色”(這或者是另一個(gè)不使用它的理由)。“特色”的主要問題是Object的構(gòu)造
函數(shù)可接受參數(shù),并且它會(huì)根據(jù)傳入的值來決定是否將對(duì)象的創(chuàng)建委托給另一個(gè)內(nèi)置構(gòu)造函數(shù),而最終返回的對(duì)象可能不是你所預(yù)期的,例如:
[javascript]view plaincopy
// Warning: antipatterns ahead
// an empty object
var o = new Object();
console.log(o.constructor === Object); // true
// a number object
var o = new Object(1);
console.log(o.constructor === Number); // true
var stringObj = ‘’;
var arrayObj = [];
var obj = {};
var stringObj = new String();
var arrayObj = new Array();
var obj = new Object();
更聰明的使用getCmp:
它將根據(jù)傳遞的id值返回匹配的對(duì)象(Ext
JS對(duì)象)。這是一種快速返回對(duì)象的方法。所有對(duì)象在創(chuàng)建的時(shí)候,都需要使用他們的id作為關(guān)鍵字注冊(cè)為一個(gè)單一對(duì)象,這樣,使用
Ext.getCmp(myId)就可以尋找并返回RegistrationObject["myId"],因此,這會(huì)變得非??旖?。
不過,如果都個(gè)組件使用了相同的id,它就會(huì)失效。在這種情況下,它將會(huì)返回最后一個(gè)查找到的對(duì)象?;谶@點(diǎn),建議盡量不要使用這個(gè)來獲取對(duì)象。建議的做法是只使用該方法一次,然后將結(jié)果保存到一個(gè)變量,再在其他地方通過變量來引用對(duì)象。
如果需要為多個(gè)組件定義相同的id,建議使用itemId。通過這篇文章可了解id和itemId直接的不同。
避免不比亞的全局變量:
使用全局變量的主要問題就是它可在javascript應(yīng)用程序或Web頁(yè)面中共享所有代碼。這可能會(huì)與使用相同名稱的命名空間引起沖突,在應(yīng)用程序的兩
個(gè)單獨(dú)部分定義具有相同名稱但用途不同的全局變量的可能性是存在的。使用不必要的全局變量的第二個(gè)缺點(diǎn)是會(huì)造成更大的內(nèi)存損耗,這是因?yàn)?,?duì)于這些全局變
量,一般情況下是不會(huì)進(jìn)行垃圾回收的,因而不會(huì)釋放內(nèi)存。
使用var關(guān)鍵字來定義全局變量:使用var來定義全局變量與不使用之間的一個(gè)細(xì)微差別是:能不能使用delete操作符來刪除這些變量。
使用var來定義的全局變量(包括在函數(shù)內(nèi)創(chuàng)建的)不能使用delete來刪除,例如:
[javascript]view plaincopy
// define three globals
var global_var = 1;
global_novar = 2; // antipattern
(function () {
global_fromfunc = 3; // antipattern
}());
// attempt to delete
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true
// test the deletion
typeof global_var; // "number"
typeof global_novar; // "undefined"
typeof global_fromfunc; // "undefined"
嘗試去刪除那些未使用的變量和函數(shù):不要保留代碼中那些沒有使用到的變量、函數(shù)或者不必要的注釋,因?yàn)檫@些只會(huì)增加文件的大小,從而增加文件的加載時(shí)間。
避免在循環(huán)中創(chuàng)建對(duì)象或變量:如果沒有必要,就不要在循環(huán)中創(chuàng)建單一的變量或?qū)ο?,因?yàn)樗麄兊臄?shù)量會(huì)隨著選好的迭代次數(shù)而增加,進(jìn)而造成內(nèi)存泄漏。
避免過度使用面板:
在大多數(shù)情況下,Ext
JS應(yīng)用程序會(huì)受到面板過度使用的影響。無論什么情況都使用面板,或者更準(zhǔn)確的說,是無論任何情況下都會(huì)使用多個(gè)面板。解決辦法就是在使用一些輕量級(jí)的替
代品來代替面板。很多人都喜歡面板,不過說實(shí)在,在UI的許多部分有點(diǎn)過分了。我曾經(jīng)看到一個(gè)用來顯示幾十個(gè)縮略圖的UI,每個(gè)圖像都是使用不同面板的
HTML內(nèi)容來顯示的,而這些面板是完全沒必要的??梢钥紤]以下替代方法……
避免容器嵌套:盡量避免不必要地使用容器,因?yàn)槊總€(gè)容器都會(huì)創(chuàng)建一個(gè)層次結(jié)構(gòu),并以此為核心來訪問子組件,而這,需要遍歷這些容器的層次結(jié)構(gòu)。因此,要盡量在最小的可能容器數(shù)量下創(chuàng)建視圖。函數(shù)要盡可能小:
每一個(gè)函數(shù)都應(yīng)短小精干和有意義。大的函數(shù)會(huì)降低可讀性、可維護(hù)性、可重用性和可調(diào)試性。除此之外,如果一個(gè)對(duì)象(非常消耗內(nèi)存的對(duì)象)在函數(shù)開始時(shí)進(jìn)行
實(shí)例化,它就會(huì)一直存在到函數(shù)結(jié)束。所以,如果函數(shù)非常小,那么,它的局部變量、對(duì)象等垃圾就可以在更短的時(shí)間跨度內(nèi)被回收,從而釋放內(nèi)存于其他用途。盡量避免過長(zhǎng)的對(duì)象引用:應(yīng)盡量避免大型對(duì)象的引用,因?yàn)檫@需要花費(fèi)更多的時(shí)間來遍歷對(duì)象的層次結(jié)構(gòu)來獲取所需的組件,例如:[javascript] view plaincopy以上代碼可重寫為以下更有效的方式:[javascript] view plaincopy
var arrayLength = arrayObj.lenght;
var obj = Abc.xyz.foo.bar.againFoo.againBar.finalObj;
for( var I = 0; I < arrayLenght; i++){
//pattern
If(obj === arrayObj[i]){
Alert(‘pattern code’);
}
}
var arrayLength = arrayObj.lenght;
for( var I = 0; I < arrayLenght; i++){
//anti pattern
If(Abc.xyz.foo.bar.againFoo.againBar.finalObj === arrayObj[i]){
Alert(‘Anti pattern code’);
}
}
應(yīng)避免吊裝(hoisting)問題:javascript
允許在一個(gè)函數(shù)內(nèi)任何個(gè)地方使用多個(gè)var語(yǔ)句,而他們的行為與在函數(shù)頂部定義變量是沒有區(qū)別的,這種行為通常被稱為吊裝。在使用變量之后再在函數(shù)內(nèi)進(jìn)行
聲明,可能會(huì)導(dǎo)致邏輯錯(cuò)誤。對(duì)于javascript來說,只要變量在同一作用域(同一函數(shù))被使用,它就會(huì)被聲明,無論是否使用了var來定義,例如:[javascript] view plaincopy第一個(gè)alert將會(huì)顯示“underfined”,這是因?yàn)閙yname被認(rèn)為是在函數(shù)內(nèi)部的局部變量(盡管是在之后聲明的)。所以變量的定義都會(huì)被吊裝到函數(shù)頂部。因此,要避免這種混亂,最好的方式就是在前期聲明所有打算使用到的變量。
// antipattern
myname = "global"; // global variable
function func() {
alert(myname); // "undefined"
var myname = "local";
alert(myname); // "local"
}
func();
創(chuàng)建高效的for循環(huán):使用for循環(huán)來遍歷javascript集合,應(yīng)將集合的長(zhǎng)度緩存到一個(gè)變量,并使用改變量作為for循環(huán)的條件,例如:[javascript] view plaincopy
for (var i = 0; i < myarray.length; i++) { //antipattern use of collection length
// do something with myarray
}
//Right pattern
var arrLength = myarray.length;
for (var i = 0; i < arrLength; i++) {
// do something with myarray
}
使用hasOwnProperty:在遍歷對(duì)象的屬性的時(shí)候,使用hasOwnProperty方法來過濾原型鏈屬性是相當(dāng)重要的,例如:[javascript] view plaincopy在定義了man之前,對(duì)象原型添加了一個(gè)有用的名為clone的方法。原型鏈的存在意味著所以對(duì)象都會(huì)自動(dòng)獲得該新方法。為了避免在枚舉man的時(shí)候顯示clone方法,就需要調(diào)用hasOwnProperty方法來過濾原型方法,例如:[javascript] view plaincopy
// 1.
// for-in loop
for (var i in man) {
if (man.hasOwnProperty(i)) { // filter
console.log(i, ":", man[i]);
}
}
/*
result in the console
hands : 2, legs : 2, heads : 1
*/
// 2.
// antipattern:
// for-in loop without checking hasOwnProperty()
for (var i in man) {
console.log(i, ":", man[i]);
}
/*
result in the console
hands : 2, legs : 2, heads : 1, clone: function()
*/
var man = {hands: 2, legs: 2, head: 1};
//somewhere else in the code
// a method was added to all object
If( typeof Object.prototype.clone === undefined){
Object.prototype.clone = function(){};
}
使用===代替==:javascript
在比較隱式類型變量的時(shí)候,會(huì)進(jìn)行類型轉(zhuǎn)換,而這也就是為什么在比較“false== 0”或“"" ==
0”時(shí)返回true的原因。為了避免因隱式類型轉(zhuǎn)換所造成的混亂,在比對(duì)值與不同的類型表達(dá)式的時(shí)候,應(yīng)始終使用===或!==操作符來進(jìn)行檢查。[javascript] view plaincopy另一學(xué)派的觀點(diǎn)是,當(dāng)使用==已經(jīng)足矣的時(shí)候,使用===就顯得有掉多余,例如,當(dāng)使用typeof的時(shí)候,明確返回的是字符串,這時(shí)候就沒必要使用恒等。不過JSLint要求嚴(yán)格的相等,它要求代碼保持一致的外觀以及減少閱讀代碼的精力(這個(gè)==是故意還是遺漏?)。
var zero = 0;
if (zero === false) {
// not executing because zero is 0, not false
}
// antipattern
if (zero == false) {
// this block is executed...
}
不要使用eval:一定要記住“eval是魔鬼”這句口頭禪。這個(gè)函數(shù)可接受任意的字符串,并將字符串作為javascript代碼執(zhí)行,例如:[javascript] view plaincopy因此,在這里使用eval會(huì)將un定義為一個(gè)數(shù)字直接量。假如把jsstrig的值作為用戶的輸入值,這將會(huì)導(dǎo)致不少的安全問題。所以,使用eval會(huì)帶來安全隱患。
console.log(typeof un); // "undefined"
var jsstring = "var un = 1; console.log(un);";
eval(jsstring); // logs "1"
console.log(typeof un); // "number"
parseInt的正確用法:正確使用parseInt的redix可以避免一些不必要的結(jié)果,例如:[javascript] view plaincopy因此,要永遠(yuǎn)記住使用第二個(gè)變量,即redix,來定義數(shù)字的類型,無論它是十進(jìn)制、八進(jìn)制還是十六進(jìn)制。
alert(parseInt("8")); // "Will print 8"
alert(parseInt("08")); // "Will print 0"
alert(parseInt("08,10")); // "Will print 8"
If we use parseInt(“08”), it gives octal value of 08.
小心函數(shù)吊裝:該問題類似于上面討論的變量吊裝。他們唯一的區(qū)別是只在使用函數(shù)聲明才會(huì)發(fā)生,而不是匿名函數(shù)。函數(shù)聲明這種情況,函數(shù)聲明被吊裝時(shí),不單只是聲明問題,處理不當(dāng)就會(huì)出現(xiàn)一些非預(yù)想的結(jié)果,例如:[javascript] view plaincopy在
示例中,會(huì)看到就像普通變量一樣,無論foo或bar自身位于hoistMe的任何地方,都會(huì)將他們移動(dòng)到頂部,重寫全局的foo和bar。不同的地方是
本地(local)的foo定義被吊裝到頂部并能正常工作,盡管它是在后面定義的。而bar的定義則不會(huì)被吊裝,只是進(jìn)行了聲明。這就是為什么直到代碼執(zhí)
行到bar的定義,會(huì)發(fā)現(xiàn)它是undefined且不能作為函數(shù)使用(同時(shí)阻止了全局的bar出現(xiàn)在作用域鏈中)。
// antipattern
// for illustration only
// global functions
function foo() {
alert('global foo');
}
function bar() {
alert('global bar');
}
function hoistMe() {
console.log(typeof foo); // "function"
console.log(typeof bar); // "undefined"
foo(); // "local foo"
bar(); // TypeError: bar is not a function
// function declaration:
// variable 'foo' and its implementation both get hoisted
function foo() {
alert('local foo');
}
// function expression:
// only variable 'bar' gets hoisted
// not the implementation
var bar = function () {
alert('local bar');
};
}
hoistMe();
將屬性添加到全局命名空間:在將一個(gè)屬性添加到全局命名空間或全局對(duì)象的時(shí)候,要小心,或許這已經(jīng)存在了,可能會(huì)覆蓋掉他們。因此,在添加一個(gè)屬性或創(chuàng)建命名空間之前,最好先檢查一下它是否存在,例如:[javascript] view plaincopy為了避免在全局命名空間創(chuàng)建任何成員時(shí)編寫這些樣板代碼,可以創(chuàng)建一些可重用的代碼,將要?jiǎng)?chuàng)建的對(duì)象傳遞過去,讓代碼去執(zhí)行上述驗(yàn)證并決定添加或放棄對(duì)象。
// unsafe and antipattern
var MYAPP = {};
// better
if (typeof MYAPP === "undefined") {
var MYAPP = {};
}
// or shorter
var MYAPP = MYAPP || {};
利用JSLint:JSLint
會(huì)獲取javascript源代碼并掃描他們。如果發(fā)現(xiàn)問題,它會(huì)返回問題描述和大致位置的消息。問題不一定是語(yǔ)法錯(cuò)誤,盡管經(jīng)常會(huì)是。JSLint專注
于一些風(fēng)格約定和結(jié)構(gòu)問題。這并不能說明你的程序是正確,只是提供一些方式來協(xié)助發(fā)現(xiàn)問題。只需要簡(jiǎn)單的粘貼腳本,它就可以快速的掃描代碼并找出任何明顯
的問題和錯(cuò)誤。網(wǎng)址:http://www.jslint.com/避免使用with語(yǔ)句:乍看上去,With語(yǔ)句看上去不賴,主要原因是它可以提供一種簡(jiǎn)單方式來訪問嵌套很深的對(duì)象,例如:[javascript] view plaincopy代替:[javascript] view plaincopy不幸的是,經(jīng)過一些測(cè)試后,會(huì)發(fā)現(xiàn)他們?cè)谠O(shè)置新成員時(shí)的表現(xiàn)非常糟糕,替代方法是,可以使用var:[javascript] view plaincopy
var o = being.person.man.bodyparts;
o.arms = true;
o.legs = true;
being.person.man.bodyparts.arms = true;
being.person.man.bodyparts.legs= true;
with (being.person.man.bodyparts) {
arms = true;
legs = true;
}
使用Ext JS內(nèi)部函數(shù)來添加或移除Ext JS組件的元素:要將一些對(duì)象添加到Ext JS容易,不建議使用以下代碼:[javascript] view plaincopy以上代碼的問題:如果使用以上代碼將一些東西添加到容易,Ext JS的所有內(nèi)部任務(wù)就不會(huì)在將對(duì)象添加到容器時(shí)執(zhí)行,而這將會(huì)引起一些問題。解決:應(yīng)使用容器的add方法,或使用組件其他類似的內(nèi)部函數(shù)來處理。
componentObj.items.items[0] = newObject;
從Ext JS的組件中返回組件:要從Ext JS的組件中返回對(duì)象,不要使用以下代碼:[javascript] view plaincopy問題:如果在上述層次結(jié)構(gòu)加入了一個(gè)新的層,如一個(gè)面板或容器,那么整個(gè)層次結(jié)構(gòu)就會(huì)變得不穩(wěn)定,可能會(huì)返回錯(cuò)誤的結(jié)果。解決:使用Ext.getCmp或queryById來代替過長(zhǎng)的層級(jí)遍歷。盡管這比層級(jí)遍歷要慢,但可保證不會(huì)出現(xiàn)以上所說層次問題。(譯者注:在4中,可使用down或up方法查詢子組件或父組件)
var anObj = componentObject.items.items[0].items.items[1];
編寫可讀、可調(diào)試和可重用的代碼:在編寫代碼時(shí),開發(fā)人員應(yīng)創(chuàng)建短小且有意義的類或函數(shù)。不要試圖去把大量的代碼寫在一個(gè)單獨(dú)的塊中。盡量保持代碼塊短小,從而讓它跟易于重復(fù)使用,且更易于閱讀。使用get/set方法:
如果使用config配置項(xiàng)來定義類的變量,Ext
JS會(huì)自動(dòng)創(chuàng)建變量的修改方法(setter)和訪問方法(getter),使用這些修改方法和訪問方法可提供代碼的可讀性。如果使用這些方法來而不是直
接使用變量名,還可以重寫這些方法或?yàn)檫@些方法添加功能。因此,應(yīng)盡可能使用訪問方法和修改方法作為類這層的變量并使用他們。永遠(yuǎn)不要使用自動(dòng)布局來創(chuàng)建組件:一些常見的錯(cuò)誤就是因?yàn)镋xt JS開發(fā)人員在創(chuàng)建容器的時(shí)候忘記為他們定義布局了。盡管這在一些瀏覽器上或特定版本的瀏覽器會(huì)運(yùn)行得很好,但從長(zhǎng)遠(yuǎn)來看,這會(huì)導(dǎo)致某些部件出現(xiàn)黑屏或失真等問題,例如:[javascript] view plaincopy在這里,在面板中沒有定義布局,面板的高度和寬度將不會(huì)根據(jù)它的組件的flex值進(jìn)行分配。原因就是容器的布局不知道如何將容器的高度和寬度分配給容器的組件。如果把“l(fā)ayout:hbox”的注釋去掉,這兩個(gè)按鈕將會(huì)根據(jù)父容器調(diào)整寬帶和高度。
Ext.create(‘Ext.panel.Panel’,{
height: 200,
width: 500,
//layout: ‘hbox’, // anti pattern if layout is not defined
items:[
{
xtype: ‘button’,
id: ‘button1’
flex: 1
},{
xtype: ‘button’,
id: ‘button2’
flex: 1
}
]
});
避免使用固定的高度和寬度:
千萬(wàn)不要在應(yīng)用程序中固定任何容器或組件的高度和寬度,因?yàn)檫@會(huì)破壞應(yīng)用程序的布局流動(dòng)性。盡量將最頂層的容器或viewport的高度和寬度定義為屏幕
大小,然后小心的通過正確的使用flex或布局將這個(gè)尺寸分分派給子組件或子容器,不要使用硬編碼的高度或?qū)挾?,也可以通過使用Ext
JS的功能來計(jì)算,如Ext.getBody().getViewSize().height或Ext..getBody().width:[javascript] view plaincopy
Ext.create(“Ext.panel.Panel”,{
height: Ext.getBody().getViewSize().height,
width: Ext.getBody().getViewSize().width
);
正確使用flex關(guān)鍵字:flex
是一個(gè)用來保持流動(dòng)性布局的非常重要的關(guān)鍵字,該值通常用來決定如何接收父容器的尺寸,例如,如果兩個(gè)組件的定義分別為flex=1和flex=2,那
么,這兩個(gè)組件從父容器接收到的尺寸比例就是1:2。在這里,還需要留意另一個(gè)重點(diǎn),就是該值只用來劃分父容器的寬度或高度,而不能同時(shí)來決定子組件的寬
度和高度,例如:[javascript] view plaincopy以
上代碼,使用了水平盒子布局,因而,只有按鈕的寬度會(huì)根據(jù)flex值的比例進(jìn)行劃分,而兩個(gè)按鈕的高度則會(huì)是100%,即是每個(gè)按鈕的寬度會(huì)是250,而
高度是200。同樣,如果將面板的布局修改為垂直盒子布局,那么,每一個(gè)按鈕的寬度將會(huì)是500,而高度會(huì)是100。因此,要適當(dāng)并謹(jǐn)慎地使用flex來
實(shí)現(xiàn)更好的流動(dòng)布局。
Ext.create(‘Ext.panel.Panel’,{
height: 200,
width: 500,
layout: ‘hbox’,
items:[
{
xtype: ‘button’,
id: ‘button1’
flex: 1
},{
xtype: ‘button’,
id: ‘button2’
flex: 1
}
]
});
盡量少用minxWidth、maxWidth、minHeight和maxHeight:盡量在需要的時(shí)候才使用這些屬性,否則就不要使用他們,因?yàn)樵诮M件布局方面,他們的使用是非常昂貴的。如果在組件中碰到這些屬性,布局會(huì)重新進(jìn)行計(jì)算,因此,這樣的代價(jià)非常昂貴。使用Sencha Cmd工具來壓縮(minification)代碼:
進(jìn)行壓縮處理時(shí),會(huì)消除空白、注釋和javascript代碼中其他不重要的部分,這樣可減少javascript文件的大小,從而減小
服務(wù)器到瀏覽器的
傳輸量。另外,壓縮處理還會(huì)重命名變量為較短的名稱(但只有在它是安全的時(shí)候),如前面代碼中的參數(shù)D、C、B或A。壓縮處理只會(huì)重命名局部變量,因?yàn)橹?命名全局變量可能破壞代碼。這也是為什么使用局部變量是一個(gè)好做法的主要愿意。如果在一個(gè)函數(shù)內(nèi),使用全局變量,如DOM引用,超過一到兩次,那就給它分
配一個(gè)局部變量,這是好的做法。這些通常需要一些工具(壓縮)來實(shí)現(xiàn),如Ext JS命令行工具(只適用于Ext
JS的應(yīng)用程序開發(fā))、雅虎的YUICompressor或谷歌的Closure
Complier(適用于普通的javascript應(yīng)用程序),這喲這樣加快頁(yè)面加載時(shí)間。壓縮為生產(chǎn)準(zhǔn)備的腳本是十分重要的,因?yàn)樽罱K可以將文件的大
小大大壓縮,通常可以壓縮一半的大小。保持DOM的輕量化:盡量保持DOM的輕量
化可加快DOM的訪問和維護(hù)速度。這可通過移除不必要的DOM元素來實(shí)現(xiàn),例如,如果使用卡片布局,且每個(gè)卡片都要顯示大量容器或組件,而且用戶不會(huì)返回
之前的卡片,最好的方式就是在程序(這樣所需的容器或組件就不會(huì)再次創(chuàng)建)中緩存DOM元素,然后將DOM元素從DOM中移除以讓它輕量化。盡量減少DOM訪問:DOM訪問是昂貴的,它是javascript性能最常見的瓶頸。這是因?yàn)镈OM的實(shí)現(xiàn)通常是與javascript引擎分離的。底線就是應(yīng)將DOM訪問減少到最低限度,這意味著:
不要?jiǎng)?chuàng)建內(nèi)聯(lián)處理函數(shù):千萬(wàn)必要?jiǎng)?chuàng)建內(nèi)聯(lián)函數(shù),因?yàn)閷?duì)于回調(diào)會(huì)監(jiān)聽所使用的函數(shù)來說,是常見的問題源。他們不單需要花費(fèi)時(shí)間來創(chuàng)建,還需要昂貴的閉包,例如:[javascript] view plaincopy以上代碼,每當(dāng)構(gòu)造函數(shù)執(zhí)行一次,就會(huì)創(chuàng)建一個(gè)新的監(jiān)聽函數(shù),這不單需要花費(fèi)時(shí)間處理閉包問題,還潛在內(nèi)存泄漏問題。以下是首選的模式:[javascript] view plaincopy在以上代碼中,監(jiān)聽函數(shù)只會(huì)創(chuàng)建一次并保存在類中。每個(gè)實(shí)例都會(huì)共享相同的函數(shù)。創(chuàng)建函數(shù)的開銷只有一次,而且沒有閉包泄漏的風(fēng)險(xiǎn)。更重要的是,這樣的編碼風(fēng)格,還可以讓子類輕松的去重寫監(jiān)聽。
Ext.define(‘MyClass’,{
constructor: function(config){
this.store.on(‘load’, this.onStoreLoad, this);
},
onStoreLoad: function(){
………;
}
});
Ext.define(‘MyClass’,{
constructor: function(config){
this.store.on(‘load’, function(){
………..;
}, this);
}
});
正確使用xtype:一個(gè)常見的神話就是xtype可通過延遲初始化提高性能。通常,這不是真的。盡管通過xtype配置項(xiàng)將組件添加到容器,它還是進(jìn)行實(shí)例化,盡管它還不可見。雖然xtype有很大用途,但對(duì)于應(yīng)用程序的性能或資源消耗來說沒有實(shí)際可衡量的影響。千萬(wàn)不要使用整個(gè)ext-all.js庫(kù):
通常,ext-all.js是包含了全部功能和組件的巨大編碼集,但我們很少會(huì)使用到Ext
JS的全部功能和組件,因此,沒必要在只使用了60%到70%代碼的時(shí)候去加載一個(gè)巨大的文件??梢允褂肧encha命令行工具來壓縮生產(chǎn)代碼,它會(huì)從
ext-all.js中復(fù)制所需的類并粘貼到結(jié)果all-classes.js。如果沒有使用Sencha命令行工具,還可以通過其他方式來確保不用加載
整4個(gè)ext-all.js文件。批處理任務(wù):盡量使用批處理進(jìn)行更新,以便渲染只在最后時(shí)刻觸發(fā)一次渲染。例如,修改記錄的字段值會(huì)立即更新到網(wǎng)格,如果想讓幾個(gè)字段的更新更高效,就進(jìn)行批處理,例如:[javascript] view plaincopy如果要修改的字段更多,效果會(huì)更明顯。另一個(gè)例子是將組件添加到容器,每添加一次,容器就會(huì)重新計(jì)算布局一次。將多個(gè)組件傳遞給同一個(gè)add方法,將會(huì)高效得多,例如:[javascript] view plaincopy在沒有其他批處理機(jī)制的時(shí)候,可以使用暫停布局來臨時(shí)輔助實(shí)現(xiàn):[javascript] view plaincopy
container.suspendLayout = true;
doSomethingToChangeLotsOfLayoutChange();
container.suspendLayout = false;
container.doLayout();
//slow code
container.add(panel);
container.add(button);
container.add(grid);
//fast
container.add(panel, button, grid);
//using an array is also fast
container.add([panel, button, grid]);
record.beginEdit();
record.set(‘name’, ‘Tom’);
record.set(‘a(chǎn)ge’, 17);
record.set(‘member’, true);
record.endEdit();
使用deferredRender:
在使用卡片布局或標(biāo)簽面板的時(shí)候,要認(rèn)真考慮一下deferredRender選項(xiàng)。當(dāng)將它設(shè)置為true,就可以將隱藏的條目或選項(xiàng)卡實(shí)現(xiàn)延遲渲染。只
有在隱藏的條目第一次顯示的時(shí)候,才會(huì)進(jìn)行渲染。當(dāng)設(shè)置為false,所以的卡片或標(biāo)簽就會(huì)作為容器渲染的一部分在同一時(shí)間進(jìn)行渲染。延遲渲染通常來說挺好的,這有助于將渲染過程分解為較小的數(shù)據(jù)塊,不會(huì)對(duì)用戶造成明顯的延遲。不過,渲染所有的卡片或標(biāo)簽頁(yè),在隱藏的卡片或標(biāo)簽頁(yè)第一次顯示的時(shí)候有助于改善UI的響應(yīng)。網(wǎng)格的緩沖渲染:在使用網(wǎng)格的時(shí)候,如果數(shù)據(jù)集很打,使用緩沖渲染吧。這意味著在加載存儲(chǔ)的時(shí)候,存儲(chǔ)要維持一個(gè)“預(yù)讀”緩沖,以保存將要使用到的記錄頁(yè)。如果數(shù)據(jù)少于100000行(也取決于每行的列數(shù)),最好的方式是在客戶端將所有數(shù)據(jù)保存到預(yù)讀緩沖區(qū)。渲染大的HTML表格會(huì)謀殺性能。這事實(shí)上只是HTML表格算法,只保持所以數(shù)據(jù)應(yīng)該不會(huì)導(dǎo)致問題。要做的只是滾動(dòng)的時(shí)候,在“適當(dāng)時(shí)候”渲染表格的行。要做到這一點(diǎn),只需要一次加載預(yù)讀緩沖中的所有數(shù)據(jù)。這樣做后,就可以從預(yù)讀緩存中加載存儲(chǔ)的主要數(shù)據(jù),例如:[javascript] view plaincopy預(yù)
讀所有所預(yù)期的數(shù)據(jù)集后,回調(diào)會(huì)加載存儲(chǔ)的主緩存(映射到網(wǎng)格面板內(nèi)的緩存)所使用的50行數(shù)據(jù)。由于只能得到小于50行的表格,所以在滾動(dòng)接近視圖邊界
的時(shí)候,它就會(huì)更新。該技術(shù)在4.0.x工作OK,不過在4.1.0進(jìn)行了翻修,變得更快和更平滑。在網(wǎng)格目錄的緩沖網(wǎng)格示例延時(shí)該技術(shù)。要注意的是,太多的列會(huì)對(duì)HTML的性能產(chǎn)生影響。元素太多也會(huì)這樣,因而需要避免顯示不需要的列。
myStore = ……{
………….,
Buffered: true, // Tell grid to use a paging scroll manager to scroll and refresh table automatically.
perPageCount: 0 // never remove pages from the prefetch buffer;
}
myStore.prefetch({
start: 0,
limit: 999999,
callback: function(){
myStore.load(0, 49);
}
});
在標(biāo)簽面板的每個(gè)標(biāo)簽頁(yè)的beforeRender事件處理中填充標(biāo)簽頁(yè):
在beforeRendere中填充標(biāo)簽頁(yè)是更好的方法。正確的實(shí)現(xiàn)這個(gè)可以有效的改進(jìn)包含大量未渲染組件的應(yīng)用程序的性能。雖然實(shí)例化一個(gè)組件的時(shí)間比
渲染或布局所需要的時(shí)間要小,但如果有大量的未渲染組件也需要時(shí)間。帶有許多標(biāo)簽頁(yè)的標(biāo)簽面板這樣處理會(huì)更理想。要特別支出的是,我建議的只是
shuffle time around:cut the time taken for the initial load in favour of
slightly slower tab
transitions.這只是你武器庫(kù)中的另一種技術(shù)。與以往一樣,優(yōu)化的黃金規(guī)則是在實(shí)現(xiàn)之前,要做一些有意義的測(cè)量。使用mon代替on:這兩個(gè)關(guān)鍵字都是用來事件處理綁定到事件的。不過,使用mon而不是on會(huì)更高效,因?yàn)檫@可確保監(jiān)聽會(huì)在MyClass的實(shí)例被銷毀的時(shí)候自動(dòng)移除它,例如:[javascript] view plaincopy
Ext.define(‘MyClass’,{
Constructor: function(config){
//this.store.on(‘load’, this.onStoreLoad, this); // this is not good
this.store.mon(‘load’, this.onStoreLoad, this);
},
onStoreLoad: function(){
………;
}
});
在事件處理程序中不要保留對(duì)this的引用:
通常,在任何Ext
JS組件的內(nèi)聯(lián)事件處理函數(shù)工作時(shí),都需要使用this關(guān)鍵字來獲取相應(yīng)類的對(duì)象的應(yīng)用。通常情況下,組件的事件處理程序的this指向的是該組件這個(gè)對(duì)
象。隱藏,要解決這個(gè)問題,一些開發(fā)人員會(huì)在構(gòu)造函數(shù)或類的initComponent方法內(nèi)使用一些全局變量來引用類,然后在內(nèi)聯(lián)處理中使用全局變量來
獲取相應(yīng)的類對(duì)象,不過,這是錯(cuò)誤的做法,我們贏遵循這里的約定。嘗試使用客戶端緩存:
本地存儲(chǔ)、session存儲(chǔ)、sqllite等等。如果使用HTML5,就可以將一些數(shù)據(jù)保持在客戶端(不是cookie),并在再次瀏覽該頁(yè)時(shí)使用這
些數(shù)據(jù)。這樣,就可以避免將一些沒必要的東西發(fā)送到服務(wù)器或數(shù)據(jù)庫(kù)。在Ext JS,可以使用代理來處理這類緩存。在Ext
JS中有兩類代理:ClientProxy和ServerProxy。ClientProxy就是用來處理客戶端緩存的。有以下三種類型的
ClientProxy:除了這些,一些瀏覽器,如chrome,還支持一些特殊類型的客戶端數(shù)據(jù),如SQLLite,它可以在客戶端存儲(chǔ)一些數(shù)據(jù)。因此,通過使用這些技術(shù),可以用來提高應(yīng)用程序的性能。
不要使用Array.isArray:Array.isArray(anyObject)
方法用來判斷anyObject是否一個(gè)數(shù)組對(duì)象。該方法只能在Chrome中工作,不能在IE中工作。IE并不能識(shí)別該方法并會(huì)給出錯(cuò)誤??墒褂?instanceof來替代該方法來達(dá)到相同的目的。instanceof方法既可在IE工作,也可在Chrome工作。一定要注意日期格式:在解析日期的時(shí)候,要注意日期字符串的格式是否既支持IE,又支持chrom:[javascript] view plaincopy不要使用var dateString = "Oct/02/2011",IE不支持,在chrome中是支持的。我已經(jīng)在應(yīng)用程序修正了這個(gè)。
var dateString = "03/20/2008";
var dateString = "2008/03/20";
var dateString = "03-20-2008";
var dateString = "March 20, 2008";
var dateString = "Mar 20, 2008";
var dateString = "Oct 2, 2011";
別忘了以下要點(diǎn):以下是在將代碼發(fā)布為產(chǎn)品時(shí)不應(yīng)忘記的一些要點(diǎn):沒有尾隨逗號(hào)即使只有一行注釋,也要使用多行注釋來代替單行注釋沒有調(diào)試的代碼要留下注釋在預(yù)期的情況下,不要丟失任何分號(hào)不要在生產(chǎn)代碼中使用console.log
作者會(huì)持續(xù)更新這篇文章。如果你有任何意見會(huì)反饋,可聯(lián)系作者。
新聞名稱:【翻譯】ExtJS——高效的編碼風(fēng)格指南
文章URL:
http://weahome.cn/article/jdpjop.html