欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JQuery each()函數(shù)如何優(yōu)化循環(huán)DOM結構的性能

 更新時間:2012年12月10日 10:38:53   作者:  
each()方法能使DOM循環(huán)結構簡潔,不容易出錯。each()函數(shù)封裝了十分強大的遍歷功能,使用也很方便,它可以遍歷一維數(shù)組、多維數(shù)組、DOM, JSON 等等在javaScript開發(fā)過程中使用$each可以大大的減輕我們的工作量
如果對jQuery這東西只停留在用的層面,而不知其具體實現(xiàn)的話,真的很容易用出問題來。這也是為什么近期我一直不怎么推崇用jQuery,這框架的API設定就有誤導人們走上歧途之嫌。
復制代碼 代碼如下:

$.fn.beautifyTable = function(options) {
//定義默認配置項,再用options覆蓋
return this.each(function() {
var table = $(this),
tbody = table.children('tbody'),
tr = tbody.children('tr'),
th = tbody.children('th'),
td = tbody.children('td');
//單獨內(nèi)容的class
table.addClass(option.tableClass);
th.addClass(options.headerClass); //1
td.addClass(options.cellClass); //2
//奇偶行的class
tbody.children('tr:even').addClass(options.evenRowClass); //3
tbody.children('tr:odd').addClass(options.oddRowClass); //4
//對齊方式
tr.children('th,td').css('text-align', options.align); //5
//添加鼠標懸浮
tr.bind('mouseover', addActiveClass); //6
tr.bind('mouseout', removeActiveClass); //7
//點擊變色
tr.bind('click', toggleClickClass); //8
});
};

總的來說,這段代碼不錯,思路清晰,邏輯明確,想要做什么也通過注釋說得很明白了。但是按作者的說法,當表格中有120行時,IE已經(jīng)反映腳本運行時間過長了。顯然從表現(xiàn)來看,這個函數(shù)的效率不高,甚至說極其低下。

于是,開始從代碼層面進行分析,這是一個標準的jQuery插件式的函數(shù),有個典型的return this.each(function( ) { 。.. };);形式的代碼,如果作者寫下這段代碼的時候,不是照本宣科不經(jīng)思考的話,就應該意識到jQuery的一個函數(shù)干了什么事。

簡單來說,jQuery.fn下的函數(shù),絕大部分是一個each的調(diào)用,所謂each,自然是對選擇出來的元素進行了遍歷,并對某個元素進行了指定的操作。那么看看上面一段代碼,進行了多少的遍歷,在此就假設只選擇了120行,每一行有6列,另加上1行的表頭吧:
遍歷th,添加headerClass,元素數(shù)為6。
遍歷td,添加cellClass,元素數(shù)為6*120=720。
從所有tr中找出奇數(shù)的,需要對所有tr進行一次遍歷,元素數(shù)為120。
遍歷奇數(shù)的tr,添加evenRowClass,元素數(shù)為120/2=60。
從所有tr中找出偶數(shù)的,需要對所有tr進行一次遍歷,元素數(shù)為120。
遍歷偶數(shù)的tr,添加oddRowClass,元素數(shù)為120/2=60。
遍歷所有th和td,添加text-align,元素數(shù)為120*6+6=726。
遍歷所有tr,添加mouseover事件,元素數(shù)為120。
遍歷所有tr,添加mouseout事件,元素數(shù)為120。
遍歷所有tr,添加click事件,元素數(shù)為120。
為了方便,我們簡單地假設,在遍歷中訪問一個元素耗時為10ms,那么這個函數(shù)一共用了多少時間呢?這個函數(shù)共遇上了2172個元素,耗時21720ms,即21秒,顯然IE確實應該報腳本執(zhí)行過久了。

知道了效率低下的原因,要從根本上進行解決,自然要想方設法來合并循環(huán),初略一看,按照上邊代碼中注釋里的數(shù)字,至少以下幾點是可以合并的:
3和4可以合并為一次循環(huán),從120+60+120+60變?yōu)?20,減少了240。1、2和5可以合并為一次循環(huán),從6+720+726變?yōu)?26,減少了726。6、7、8可以合并為一次循環(huán),從120+120+120變?yōu)?20,減少了240。進一步的,3、4和6、7、8一樣可以合并為一次循環(huán),繼續(xù)減少了120。累加一下,我們一共減少了240+726+240+120=1326次元素操作,總計13260ms。在優(yōu)化之后,我們的函數(shù)耗時變?yōu)?1720-13260=8460ms,即8s。
到這里可能會有一個疑問,從表格的結構上來說,所有的th和td元素肯定都在tr之內(nèi),那么為什么不將1、2、5這三步的循環(huán)同樣放到對tr的循環(huán)中,形成一個嵌套的循環(huán),這樣不是更加快速嗎?
這里之所以沒有這么做,主要有2個原因:
其一,無論將1、2、5這三者放在哪里,都不會減少對所有th和td元素的一次訪問。
另一方面,$(‘th,td')這個選擇器,在sizzle中會被翻譯成2次getElementsByTagName函數(shù)的調(diào)用,第一次獲取所有th,第二次獲取所有td,然后進行集合的歸并。由于getElementsByTagName是內(nèi)置函數(shù),在此可以認為該函數(shù)是不帶循環(huán)的,即復雜度為O(1),同樣集合的歸并使用Array的相關函數(shù),是對內(nèi)存的操作,復雜度同樣為O(1)。

反之,如果在對tr元素的循環(huán)中再采用$(‘th,'td)這個選擇器,則是在tr元素上調(diào)用2次getElementsByTagName,由于無論在哪個元素上調(diào)用該函數(shù),函數(shù)執(zhí)行的時間是相同的,因此在循環(huán)tr時使用,反而多出了119*2次的函數(shù)調(diào)用,效率不升反降。
可見,對sizzle選擇器的基本知識,也是幫助優(yōu)化jQuery代碼的很重要的一方面。
不要啥都讓javascript來做。

根據(jù)前面的基本的優(yōu)化,已經(jīng)將時間從21秒降到了8秒,但是8秒這個數(shù)字顯然是無法接受的。
再進一步分析我們的代碼,事實上,循環(huán)遍歷是語言層面上的內(nèi)容,其速度應該是相當快的。而針對每個元素所做的操作,是jQuery提供的函數(shù),相比遍歷來說,才是占去大部分資源的主子。如果說遍歷中訪問元素用時是10ms的話,不客氣地說執(zhí)行一個addClass至少是100ms級別的消耗。

因此,為了進一步地優(yōu)化效率,就不得不從減少對元素的操作入手。再仔細地回審代碼,發(fā)現(xiàn)這個函數(shù)有著非常多的對樣式的修改,其中至少包括了:
給所有th加上class。
給所有td加上class。
給tr分奇偶行加上class。
給所有th和td加上一個text-align樣式。
而事實上我們知道,CSS本身就擁有子代選擇器,而瀏覽器原生對CSS的解析,效率遠遠高于讓javascript去給元素一一加上class。

所以,如果對CSS是可控的,那么這個函數(shù)就不應該擁有headerClass、cellClass這兩個配置項,而是盡可能地在CSS中進行配置:
復制代碼 代碼如下:

.beautiful-table th { /* headerClass的內(nèi)容 */ }
.beautiful-table td { /* cellClass的內(nèi)容 */ }

再者,對于tr的奇偶行樣式,在部分瀏覽器下可以使用:nth-child偽類來實現(xiàn),這方面可以利用特性探測,僅在不支持該偽類的瀏覽器中使用addClass添加樣式。當然如果你僅僅想對IE系列進行優(yōu)化的話,這一條可以忽略了。

對于:nth-child偽類的探測,可以用以下的思路來進行:創(chuàng)建一個stylesheet,再創(chuàng)建一條規(guī)則,如#test span:nth-child(odd) { display: block; }。創(chuàng)建相應的HTML結構,一個id為test的div,內(nèi)部放置3個span。

將stylesheet和div一同加入的DOM樹中。查看第1和第3個span的運行期display樣式,如果是block,則表明支持該偽類。刪除創(chuàng)建的stylesheet和div,別忘了緩存探測的結果。最后,對于給所有th和td元素添加text-align樣式,也是可以通過css進行優(yōu)化的。既然不知道添加的是哪個align,那么就多寫幾個樣式:
復制代碼 代碼如下:

/* CSS樣式 */
.beautiful-table-center th,.beautiful-table-center td { text-align: center !important; }
.beautiful-table-rightright th,.beautiful-table-rightright td { text-align: rightright !important; }
.beautiful-table-left th,.beautiful-table-left td { text-align: left !important; }
/* javascript */
table.addClass('beautiful-table-' + options.align);

當然,上面所說的優(yōu)化,是建立在對CSS有控制權的情況下的,如果本身無法接觸到CSS樣式,比如這是一個通用的插件函數(shù),會被完全無法控制的第三方使用,那么怎么辦呢?也不是完全沒有辦法:
去找頁面里的所有CSS規(guī)則,比如document.styleSheets。遍歷所有規(guī)則,把配置項中的headerClass、cellClass等拿出來。提取需要的幾個class中的所有樣式,再自己組裝成新的選擇器,如beautiful-table th。使用創(chuàng)建出來的選擇器,生成新的stylesheet,加入到DOM樹中。那么只給table加上beautiful-table這個class就搞定了。

當然上面的做法其實也蠻消耗時間的,畢竟又要遍歷stylesheet,又要創(chuàng)建stylesheet。具體是不是對效率提升有很大的幫助,則依據(jù)頁面的規(guī)模會有不同的效果,是否使用就要看函數(shù)設計人員的具體需求了,這里也就是提一種策略。

總的來說,通過盡可能少地執(zhí)行javascript,將更多的樣式化的任務交給CSS,則瀏覽器的渲染引擎來完成,又可以進一步地優(yōu)化該函數(shù),假設對addClass、css的調(diào)用需要100ms的話,此次優(yōu)化直接消滅了原有120+726=846次的操作,節(jié)約了84600ms的時間(當然有夸張的成分,但是對整個函數(shù)的消耗來說,這個確實是很大的一塊)。

這篇文章,僅僅是想在jQuery的各個實現(xiàn)的層面上來進行優(yōu)化,只涉及到了對jQuery整個運行過程的分析、細節(jié)介紹和優(yōu)化方向,并沒有提到一些基本之基本的優(yōu)化方法,比如:先將整個table從DOM樹中移除,完成所有的操作之后再放回DOM,減少repaint。將mouseover和mouseout改為mouseenter和mouseleave,減少因為下正確的事件冒泡模型導致的重復的事件函數(shù)的執(zhí)行。對于th、td之類單純元素的選擇,優(yōu)先考慮使用原生的getElementsByTagName,消滅sizzle分析選擇器的時間。

最后,這篇文章只是想說明,對于前端開發(fā)人員,雖然瀏覽器可能是個黑盒,但是很多框架、工具、庫都是開放的,在使用之前如果可以進行一定程度的了解,必然有助于個人的技術提升和最終產(chǎn)品的質(zhì)量優(yōu)化,“知其然而不知其所以然”是非常忌諱的情況。

相關文章

最新評論