日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

ExtJS 4.1性能

系統(tǒng) 2335 0

原文: http://www.sencha.com/blog/ext-js-4-1-performance/

在本文,將講述幾個影響Ext JS應(yīng)用性能的因素。

  • 網(wǎng)絡(luò)延時會嚴(yán)重影響初始化啟動時間,尤其是Store的加載時間。
  • CSS處理。
  • Javascript的執(zhí)行。
  • DOM操作。

網(wǎng)絡(luò)延時

為了最大限度的減少應(yīng)用啟動時間,必須牢記的是,任何域?qū)g覽器的網(wǎng)絡(luò)連接并發(fā)數(shù)量是有限制。


這意味著,如果從一個域請求許多文件,一旦達(dá)到上限,隨后的下載將要排隊,只有當(dāng)一個連接槽釋放時,他們才會被處理。新的瀏覽器都有較高范圍,但對舊的、慢的瀏覽器進(jìn)行優(yōu)化就很重要。


解決辦法是使用Sencha SDK工具將應(yīng)用所需的腳本文件生成一個單一的串聯(lián)的腳本文件。


具體信息可查看 Ext JS 4.0入門 。

SDK的“create”命令會分析加載到頁面的應(yīng)用,加載類定義中requires和user屬性引用的所有文件,然后以正確的順序創(chuàng)建一個包含所有所需的類定義的腳本文件。


可在 Ext JS 4.1的文檔 中查閱Sencha類系統(tǒng)的詳細(xì)信息。

另外一種減少網(wǎng)絡(luò)延時的方法是在Web服務(wù)器對Ext JS的頁面及其相關(guān)的腳本和樣式文件啟用GZIP壓縮。

CSS處理

CSS選擇是跟隨DOM的父節(jié)點指針從右到左匹配的。

這意味著以下的樣式處理過程是,現(xiàn)在文檔中找到匹配的span,然后沿著父節(jié)點這條軸去尋找符合兩個指定樣式類名的祖先節(jié)點。

  1. .HeaderContainer.navspan

因而,在元素上使用單一的,確定類名的樣式會更高效。

Javascript執(zhí)行

優(yōu)化Javascript代碼必須牢記以下幾點:

  • 避免使用舊的或差的Javascript引擎的寫法。
  • 優(yōu)化經(jīng)常重復(fù)出現(xiàn)的代碼。
  • 優(yōu)化在渲染或布局時執(zhí)行的代碼
  • 最好是盡量不要在初始化渲染或布局時執(zhí)行任何額外的代碼。
  • 將不變的表達(dá)式移到循環(huán)外面。
  • 使用for循環(huán)代替Ext.Array.each。
  • 如果函數(shù)中條件內(nèi)代碼經(jīng)常被調(diào)用,必要時,將條件移到函數(shù)外(可參考Ext JS代碼庫對fireEvent的調(diào)用)。
  • 在差的Javascript引擎安裝和拆卸調(diào)用框架(讓函數(shù)調(diào)用所需的設(shè)備)會很慢。

代碼優(yōu)化示例

試想一下,一個統(tǒng)計應(yīng)用為Grid的數(shù)據(jù)列提供了一些操作,在Grid的列標(biāo)題菜單中增加菜單項,以便對任何調(diào)用列進(jìn)行所需的操作。


處理程序必須獲得相關(guān)的上下文信息及將要進(jìn)行操作的當(dāng)前活動的列標(biāo)題信息:

ExtJS 4.1性能

GitHub 的示例演示了兩種執(zhí)行這個操作的方式,它可以運行在任何版本的SDK示例目錄下。

以下是第一種用來合計活動列的寫法:

[javascript] view plain copy
  1. function badTotalFn(menuItem){
  2. var r=store.getRange(),
  3. total=0;
  4. Ext.Array.each(r, function (rec){
  5. total+=rec.get(menuItem.up( 'dataIndex' ).dataIndex);
  6. });
  7. }

這里有幾個錯誤做法。首先,使用Ext.each為數(shù)組中的每個記錄調(diào)用傳遞函數(shù)。正如看到的,函數(shù)設(shè)置會影響性能。其次,menuItem.up('dataIndex')表達(dá)式的結(jié)果是不變的,它只需要執(zhí)行一次,可以放到循環(huán)之外。

因此,可將代碼優(yōu)化成以下代碼:

[javascript] view plain copy
  1. function goodTotalFn(menuItem){
  2. var r=store.getRange(),
  3. field=menuItem.up( 'dataIndex' ).dataIndex;
  4. total=0;
  5. for ( var j=0,l=r.length;j<l;j++){
  6. total+=r[j].get(field);
  7. }
  8. }

這可能似乎微不足道的差異,但性能差異顯著。

在下面表格,計算功能迭代了10000次后,提供了一個可衡量的時間:

Browser Bad Good
Chrome 1700ms 10ms
IE9 18000ms 500ms
IE6 Gave up 532ms


正如所看到的,即使沒有迭代,使用第一個方式,IE9都要花費1.8秒去處理操作。

使用頁面分析器去衡量性能

頁面分析器是SDK的一個示例,在example/page-analyzer目錄可找到它。它會在捕捉框架中運行同一個域的頁面,然后捕捉Ext JS示例,以便分析布局性能和任何對象的任何方法的性能。

如果是使用Chrome,需要在它的命令行使用“-enable-benchmarking”命令開啟微秒計時精度。

要分析以上示例的關(guān)鍵位置的性能,切換到“性能”標(biāo)簽,然后在左下角的標(biāo)簽面板選擇“Accumulators”標(biāo)簽,并粘貼以下代碼到textarea:

[javascript] view plain copy
  1. {
  2. "Component.up" :{
  3. "Ext.Component" : "up"
  4. },
  5. "CQ.is" :{
  6. "Ext.ComponentQuery" : "!is"
  7. }
  8. }

確保迭代兩個合計計算函數(shù)10000次,才能獲得準(zhǔn)確的性能狀態(tài)。

然后在頁面分析器中加載Grid性能測試示例,使用“Get total in bad way”開始合計,并單擊頁面分析器的右上角“UPdate Stats”。

ExtJS 4.1性能

然后單擊“Reset”清空accumulators,增加“Build”計時器,使用“Get total in good way”進(jìn)行合計并單擊頁面分析器的“Update Stats”按鈕。

在“性能”標(biāo)簽的“Grid”子標(biāo)簽內(nèi),會看到下圖所示的兩個運行結(jié)果:

ExtJS 4.1性能

從圖中可以看到,不變表單式在循環(huán)外調(diào)用ComponentQuery方法的次數(shù)要少得多。

合并多個布局操作

Ext JS 4會根據(jù)內(nèi)容變化或大小變化自動進(jìn)行布局。這意味著,當(dāng)一個按鈕的文本變化,會導(dǎo)致它所在的工具欄重新布局(因為按鈕的高度可能會改變),而工具欄所在的面板也要重新布局(因為工具欄的高度可能改變)。

基于這個原因,在內(nèi)容或大小發(fā)生改變時,將多個布局操作合并在一起顯得非常重要,可以使用以下代碼實現(xiàn):

[javascript] view plain copy
  1. {
  2. Ext.suspendLayouts();
  3. //batchofupdates
  4. Ext.resumeLayouts( true );
  5. }

參數(shù)true的傳遞意味著重新啟用布局,它運行到這點時,會清理任何排隊的布局請求。

減少DOM負(fù)擔(dān)

通過減少嵌套的容器或組件以實現(xiàn)盡可能少的層數(shù)相當(dāng)重要,這可以避免重復(fù)布局運行和DOM回流,因為這些的開銷是很昂貴的。

另外一個要遵循的原則是使用最簡單的容器或布局做必要的工作。

常見的例子是在將一個Grid放到TabPanel的時候再嵌套一個組件。以下就是習(xí)以為常的寫法:

[javascript] view plain copy
  1. {
  2. xtype: "tabpanel" ,
  3. items:[{
  4. title: "Results" ,
  5. items:{
  6. xtype: "grid"
  7. ...
  8. }
  9. }]
  10. }

不知道為什么要添加一個普通面板作為標(biāo)簽面板的子條目,然后再面板內(nèi)放置Grid,而這樣的嵌套層毫無用處。

而事實上,這破壞了標(biāo)簽面板的運作,因為沒有為封裝的面板配置布局,從而不能處理它的子組件Grid的大小變化,這意味著它不能自適應(yīng)標(biāo)簽面板的大小,并根據(jù)標(biāo)簽面板的高度進(jìn)行滾動。

正確的寫法是:

[javascript] view plain copy
  1. {
  2. xtype:”tabpanel“,
  3. items:[{
  4. title:”Results“,
  5. xtype:”grid“,
  6. ...
  7. }]
  8. }

為什么這個原則很重要?

保持組件樹(或DOM樹)盡可能的輕量化是相當(dāng)重要的,其主要原因是在Ext JS 4中,許多組件是帶有子組件的容器并有執(zhí)行自己的布局管理器,例如,面板標(biāo)題現(xiàn)在是一個容器類,在它里面可以配置除標(biāo)題文本和工具按鈕之外的其它的組件。

雖然將標(biāo)題作為層次化的容器帶來了額外的開銷,但是這讓UI設(shè)計更靈活了。

此外,在Ext JS 4中,組件會使用組件布局管理器去管理內(nèi)部DOM結(jié)構(gòu)的大小和位置,而不象Ext JS 3.x那樣,使用onResize方法去處理。

可視化的組件樹

在遵循以上原則去設(shè)計UI的時候,可以把UI想象為樹結(jié)構(gòu),例如,一個Viewport可以想象為:

ExtJS 4.1性能

為了渲染yield組件樹,它會運作2次。

第一遍,會調(diào)用每個組件的beforeRender,然后調(diào)用getRenderTree產(chǎn)生可生成HTML標(biāo)記的DomHelper的配置對象,并將它添加到渲染緩存中。

第一遍之后,一次性將代表整樹的HTML代碼插入到文檔中,這樣,就減少了創(chuàng)建應(yīng)用結(jié)構(gòu)時的DOM處理。

然后樹再走一遍,調(diào)用每個組件onRender方法將組件連接到他們相關(guān)的DOM節(jié)點。然后調(diào)用afterRender完成渲染處理。

在此之后,完整的初始布局就執(zhí)行完了。

而這就是為什么創(chuàng)建輕量級UI非常重要的原因。

研究一下下面面板的構(gòu)成:

[javascript] view plain copy
  1. Ext.create( 'Ext.panel.Panel' ,{
  2. width:400,height:200,
  3. icon: '../shared/icons/fam/book.png' ,
  4. title: 'Test' ,
  5. tools:[{
  6. type: 'gear'
  7. },{
  8. type: 'pin'
  9. }],
  10. renderTo:document.body
  11. });

它會導(dǎo)致相當(dāng)復(fù)雜的UI結(jié)構(gòu):

ExtJS 4.1性能

盡可能避免收縮封裝(shrinkwrapping,根據(jù)內(nèi)容自動調(diào)整大?。?

盡管Ext JS 4提供了可自動根據(jù)內(nèi)容調(diào)整大小的容器(在Ext JS中簡稱為“shrinkwrapping”),但這會加重部分布局的負(fù)擔(dān),其次是計算結(jié)果會造成瀏覽器的回流,隨后還要使用計算的高度和寬度重新布局。

避免DOM刷新大小,可提高性能。

盡可能避免限制大?。╩inHeight, maxHeight, minWidth, maxWidth)

如果限制被命中,那么整個布局就要進(jìn)行重新計算,例如,一個使用flex定義的盒子布局的子組件在收到其計算寬度小于定義的minWidth時,它會被固定為最小寬度,然后整個盒子布局將不得不重新進(jìn)行計算。

類似的情形是,一個盒子布局使用stretchMax配置項時,所有子組件將切換為固定的垂直尺寸(例如,Hbox布局高度),而布局則會重新計算。

避免在渲染后處理組件的DOM

為了避免DOM回流和重畫,盡量避免在組件渲染后處理其DOM結(jié)構(gòu)。替代辦法是在生成HTML代碼之前,使用提供的鉤子去修改組件的配置。

如果實在是要修改ODM結(jié)構(gòu),重寫getRenderTree方法是最后的方式。

Grid的性能

表格的大小會影響性能,尤其是列的數(shù)量,因而要保持盡可能少的列數(shù)。

如果數(shù)據(jù)集非常大,而且不想在UI中使用分頁工具條,那么就使用俗稱為“無限Grid”的緩沖渲染方式。

要實現(xiàn)這個,只需要在Store中添加以下配置項:

[javascript] view plain copy
  1. buffered: true ,
  2. pageSize:50, //Whateverworksbestgivenyournetwork/DBlatency
  3. autoLoad: true

然后像往常一樣加載和維護(hù)它。

它是如何工作的

Grid會計算渲染表格的大小并根據(jù)PagingScroller對象的配置項來監(jiān)控滾動位置。以下是滾動時需要配置的配置項:

  • trailingBufferZone :保持在可視區(qū)域上的已渲染記錄數(shù)。
  • leadingBufferZone:保持在可視區(qū)域下已渲染的記錄數(shù)。
  • numFromEdge:在表格刷新之前,表格滾動時與可視區(qū)域之間的邊界值。

渲染的表格需要包含足夠的行數(shù)來填充視圖的高度,還要加上緩沖期的大小,以及前導(dǎo)緩沖區(qū)的大小,再加上(numFromEdge * 2)以便創(chuàng)建滾動溢出。

表格的滾動結(jié)果,會被監(jiān)控,并在表格末尾與視圖之間的行數(shù)小于numFromEdge時,使用數(shù)據(jù)集中的下一塊數(shù)據(jù)重新渲染表格,然后定位,以便讓行的可視位置不變。

在最好的情況,重新渲染所需的行已經(jīng)在頁面緩存中,而操作是瞬時的和察覺不到的。

要配置這些值,可在Grid的verticalScroller配置項中配置:

[javascript] view plain copy
  1. {
  2. xtype: 'gridpanel' ,
  3. verticalScroller:{
  4. numFromEdge:5,
  5. trailingBufferZone:10,
  6. leadingBufferZone:20
  7. }
  8. }

這意味著將有40行的溢出數(shù)據(jù)提供給Grid可視區(qū)域?qū)崿F(xiàn)平滑滾動,而重新渲染將會在表格邊界與可視區(qū)域之間少于5行時發(fā)生。

保持管道完整

保持頁面緩存為將來的滾動準(zhǔn)備數(shù)據(jù)是Store的工作。Store也有trailingBufferZone和leadingBufferZone。

每當(dāng)表格請求重新渲染的行時,在返回請求行之后,Store會確保緩存中的數(shù)據(jù)涵蓋兩個區(qū)域所需的數(shù)據(jù),如果數(shù)據(jù)不在緩存,則會向服務(wù)器請求數(shù)據(jù)。

這兩個區(qū)域都有相當(dāng)大的默認(rèn)值,開發(fā)人員可以調(diào)小或調(diào)大他們保持在管道中的頁數(shù)。

緩存失敗

當(dāng)“瞬移”到數(shù)據(jù)集不在緩存部分時,會顯示加載遮蔽和延時渲染,因為需要從服務(wù)器請求數(shù)據(jù),不過,這種情況已經(jīng)優(yōu)化過了。

包含顯示區(qū)域所需數(shù)據(jù)的頁面范圍會優(yōu)先發(fā)生請求,當(dāng)數(shù)據(jù)一到達(dá)就立刻重新渲染。 trailingBufferZone 和leadingBufferZone所需的數(shù)據(jù)將會在UI所需數(shù)據(jù)加載后立刻發(fā)送請求。


修剪緩存

默認(rèn)情況下,緩存會計算最大尺寸,除此之外,它還會丟棄最近使用的頁。頁面數(shù)量的大小為滾動條的leadingBufferZone加上可視區(qū)域大小,再加上trailingBufferZone和Store的purgePageCount配置項。增加purgePageCount意味著一旦一個頁面被訪問,就可以很快的返回它,而不是向服務(wù)器發(fā)送請求。

如果purgePageCount的值為0,意味著緩存可以不斷增長,而不用修剪,最終可能增長到包含整個數(shù)據(jù)集。這在數(shù)據(jù)集不是大得離譜時是一個非常有用的選項。記住,人類無法理解太多的數(shù)據(jù),因而在Grid顯示多于千行的數(shù)據(jù)實際上沒有多大用處,這可能意味著,他們使用了錯誤過濾條件并需要重新查詢。

將整個數(shù)據(jù)集放在客戶端

如果數(shù)據(jù)集不是天文數(shù)據(jù)集,將整個數(shù)據(jù)集緩存在頁面是可行的。

可以通過SDK示例目錄下的(examples/grid/infinite-scroll-grid-tuner.html)的“Infinite Grid Tuner”示例來測試下其可行性。

如果設(shè)置Store的leadingBufferZone為50000,并設(shè)置purgePageCount為0,這將產(chǎn)生預(yù)期的效果。

leadingBufferZone會讓Store去保持管道完整,50000意味折非常完整。

purgePageCount 為0意味著頁數(shù)的增長沒有限制。

因此,當(dāng)單擊“Reload”,會看到可視區(qū)域需要的數(shù)據(jù)頁會最先被請求,然后渲染。

然后,會看到Store會努力去填滿巨大的leadingBufferZone。很快,整個數(shù)據(jù)集就被緩存了,然后,在滾動區(qū)域任何地方的數(shù)據(jù)訪問都是即時的。


作者: Nige "Animal" White
Nigel brings more than 20 years experience to his role as a software architect at Sencha. He has been working with rich Internet applications, and dynamic browser updating techniques since before the term "Ajax" was coined. Since the germination of Ext JS he has contributed code, documentation, and design input.

ExtJS 4.1性能


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 湟中县| 山阳县| 光泽县| 西城区| 丰镇市| 五大连池市| 德庆县| 铜山县| 乌拉特后旗| 明光市| 彰化县| 新泰市| 福海县| 阳山县| 曲松县| 松滋市| 黄浦区| 嘉义市| 阳曲县| 文昌市| 三江| 宜兰县| 武安市| 乌海市| 阳谷县| 贺兰县| 定襄县| 怀远县| 永泰县| 陈巴尔虎旗| 洛宁县| 饶河县| 健康| 万山特区| 丹寨县| 仪征市| 昭苏县| 十堰市| 沙田区| 夏邑县| 安塞县|