自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

精益求精 jQuery代碼的分析與優(yōu)化

開(kāi)發(fā) 前端
,QQ群里就看到有人求助優(yōu)化一段jQuery代碼,簡(jiǎn)單看了一下,發(fā)現(xiàn)如果對(duì)jQuery這東西只停留在用的層面,而不知其具體實(shí)現(xiàn)的話,真的很容易用出問(wèn)題來(lái)。這也是為什么近期我一直不怎么推崇用jQuery,這框架的API設(shè)定就有誤導(dǎo)人們走上歧途之嫌。

今天剛回家,QQ群里就看到有人求助優(yōu)化一段jQuery代碼,簡(jiǎn)單看了一下,發(fā)現(xiàn)如果對(duì)jQuery這東西只停留在用的層面,而不知其具體實(shí)現(xiàn)的話,真的很容易用出問(wèn)題來(lái)。這也是為什么近期我一直不怎么推崇用jQuery,這框架的API設(shè)定就有誤導(dǎo)人們走上歧途之嫌。

需要優(yōu)化的代碼大致是這樣的,也不方便直接把人家的代碼復(fù)制過(guò)來(lái),就大概地表達(dá)下意思:

  1. $.fn.beautifyTable = function(options) {  
  2. //定義默認(rèn)配置項(xiàng),再用options覆蓋  
  3. return this.each(function() {  
  4. var table = $(this),  
  5. tbody = table.children('tbody'),  
  6. tr = tbody.children('tr'),  
  7. th = tbody.children('th'),  
  8. td = tbody.children('td');  
  9. //單獨(dú)內(nèi)容的class  
  10. table.addClass(option.tableClass);  
  11. th.addClass(options.headerClass); //1  
  12. td.addClass(options.cellClass); //2  
  13. //奇偶行的class  
  14. tbody.children('tr:even').addClass(options.evenRowClass); //3  
  15. tbody.children('tr:odd').addClass(options.oddRowClass); //4  
  16. //對(duì)齊方式  
  17. tr.children('th,td').css('text-align', options.align); //5  
  18. //添加鼠標(biāo)懸浮  
  19. tr.bind('mouseover', addActiveClass); //6  
  20. tr.bind('mouseout', removeActiveClass); //7  
  21. //點(diǎn)擊變色  
  22. tr.bind('click', toggleClickClass); //8  
  23. });  
  24. }; 

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

尋找原因

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

簡(jiǎn)單來(lái)說(shuō),jQuery.fn下的函數(shù),絕大部分是一個(gè)each的調(diào)用,所謂each,自然是對(duì)選擇出來(lái)的元素進(jìn)行了遍歷,并對(duì)某個(gè)元素進(jìn)行了指定的操作。那么看看上面一段代碼,進(jìn)行了多少的遍歷,在此就假設(shè)只選擇了120行,每一行有6列,另加上1行的表頭吧:

  • ·  遍歷th,添加headerClass,元素?cái)?shù)為6。
  • ·  遍歷td,添加cellClass,元素?cái)?shù)為6*120=720。
  • ·  從所有tr中找出奇數(shù)的,需要對(duì)所有tr進(jìn)行一次遍歷,元素?cái)?shù)為120。
  • ·  遍歷奇數(shù)的tr,添加evenRowClass,元素?cái)?shù)為120/2=60。
  • ·  從所有tr中找出偶數(shù)的,需要對(duì)所有tr進(jìn)行一次遍歷,元素?cái)?shù)為120。
  • ·  遍歷偶數(shù)的tr,添加oddRowClass,元素?cái)?shù)為120/2=60。
  • ·  遍歷所有th和td,添加text-align,元素?cái)?shù)為120*6+6=726。
  • ·  遍歷所有tr,添加mouseover事件,元素?cái)?shù)為120。
  • ·  遍歷所有tr,添加mouseout事件,元素?cái)?shù)為120。
  • ·  遍歷所有tr,添加click事件,元素?cái)?shù)為120。

為了方便,我們簡(jiǎn)單地假設(shè),在遍歷中訪問(wèn)一個(gè)元素耗時(shí)為10ms,那么這個(gè)函數(shù)一共用了多少時(shí)間呢?這個(gè)函數(shù)共遇上了2172個(gè)元素,耗時(shí)21720ms,即21秒,顯然IE確實(shí)應(yīng)該報(bào)腳本執(zhí)行過(guò)久了。

基本優(yōu)化

知道了效率低下的原因,要從根本上進(jìn)行解決,自然要想方設(shè)法來(lái)合并循環(huán),初略一看,按照上邊代碼中注釋里的數(shù)字,至少以下幾點(diǎn)是可以合并的:

  • ·  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。
  • ·  進(jìn)一步的,3、4和6、7、8一樣可以合并為一次循環(huán),繼續(xù)減少了120。

累加一下,我們一共減少了240+726+240+120=1326次元素操作,總計(jì)13260ms。在優(yōu)化之后,我們的函數(shù)耗時(shí)變?yōu)?1720-13260=8460ms,即8s。

注意選擇器

到這里可能會(huì)有一個(gè)疑問(wèn),從表格的結(jié)構(gòu)上來(lái)說(shuō),所有的th和td元素肯定都在tr之內(nèi),那么為什么不將1、2、5這三步的循環(huán)同樣放到對(duì)tr的循環(huán)中,形成一個(gè)嵌套的循環(huán),這樣不是更加快速嗎?

這里之所以沒(méi)有這么做,主要有2個(gè)原因:

其一,無(wú)論將1、2、5這三者放在哪里,都不會(huì)減少對(duì)所有th和td元素的一次訪問(wèn)。

另一方面,$('th,td')這個(gè)選擇器,在sizzle中會(huì)被翻譯成2次getElementsByTagName函數(shù)的調(diào)用,***次獲取所有th,第二次獲取所有td,然后進(jìn)行集合的歸并。由于getElementsByTagName是內(nèi)置函數(shù),在此可以認(rèn)為該函數(shù)是不帶循環(huán)的,即復(fù)雜度為O(1),同樣集合的歸并使用Array的相關(guān)函數(shù),是對(duì)內(nèi)存的操作,復(fù)雜度同樣為O(1)。

反之,如果在對(duì)tr元素的循環(huán)中再采用$('th,'td)這個(gè)選擇器,則是在tr元素上調(diào)用2次getElementsByTagName,由于無(wú)論在哪個(gè)元素上調(diào)用該函數(shù),函數(shù)執(zhí)行的時(shí)間是相同的,因此在循環(huán)tr時(shí)使用,反而多出了119*2次的函數(shù)調(diào)用,效率不升反降。

可見(jiàn),對(duì)sizzle選擇器的基本知識(shí),也是幫助優(yōu)化jQuery代碼的很重要的一方面。

不要啥都讓JavaScript來(lái)做

根據(jù)前面的基本的優(yōu)化,已經(jīng)將時(shí)間從21秒降到了8秒,但是8秒這個(gè)數(shù)字顯然是無(wú)法接受的。

再進(jìn)一步分析我們的代碼,事實(shí)上,循環(huán)遍歷是語(yǔ)言層面上的內(nèi)容,其速度應(yīng)該是相當(dāng)快的。而針對(duì)每個(gè)元素所做的操作,是jQuery提供的函數(shù),相比遍歷來(lái)說(shuō),才是占去大部分資源的主子。如果說(shuō)遍歷中訪問(wèn)元素用時(shí)是10ms的話,不客氣地說(shuō)執(zhí)行一個(gè)addClass至少是100ms級(jí)別的消耗。

因此,為了進(jìn)一步地優(yōu)化效率,就不得不從減少對(duì)元素的操作入手。再仔細(xì)地回審代碼,發(fā)現(xiàn)這個(gè)函數(shù)有著非常多的對(duì)樣式的修改,其中至少包括了:

  • ·  給所有th加上class。
  • ·  給所有td加上class。
  • ·  給tr分奇偶行加上class。
  • ·  給所有th和td加上一個(gè)text-align樣式。

而事實(shí)上我們知道,CSS本身就擁有子代選擇器,而瀏覽器原生對(duì)CSS的解析,效率遠(yuǎn)遠(yuǎn)高于讓javascript去給元素一一加上class。

所以,如果對(duì)CSS是可控的,那么這個(gè)函數(shù)就不應(yīng)該擁有headerClass、cellClass這兩個(gè)配置項(xiàng),而是盡可能地在CSS中進(jìn)行配置:

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

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

對(duì)于:nth-child偽類的探測(cè),可以用以下的思路來(lái)進(jìn)行:

  • ·  創(chuàng)建一個(gè)stylesheet,再創(chuàng)建一條規(guī)則,如#test span:nth-child(odd) { display: block; }。
  • ·  創(chuàng)建相應(yīng)的HTML結(jié)構(gòu),一個(gè)id為test的div,內(nèi)部放置3個(gè)span。
  • ·  將stylesheet和div一同加入的DOM樹(shù)中。
  • ·  查看第1和第3個(gè)span的運(yùn)行期display樣式,如果是block,則表明支持該偽類。
  • ·  刪除創(chuàng)建的stylesheet和div,別忘了緩存探測(cè)的結(jié)果。

***,對(duì)于給所有th和td元素添加text-align樣式,也是可以通過(guò)css進(jìn)行優(yōu)化的。既然不知道添加的是哪個(gè)align,那么就多寫幾個(gè)樣式:

  1. /* CSS樣式 */ 
  2. .beautiful-table-center th,.beautiful-table-center td { text-align: center !important; }  
  3. .beautiful-table-right th,.beautiful-table-right td { text-align: right !important; }  
  4. .beautiful-table-left th,.beautiful-table-left td { text-align: left !important; }  
  5. /* javascript */ 
  6. table.addClass('beautiful-table-' + options.align);  

當(dāng)然,上面所說(shuō)的優(yōu)化,是建立在對(duì)CSS有控制權(quán)的情況下的,如果本身無(wú)法接觸到CSS樣式,比如這是一個(gè)通用的插件函數(shù),會(huì)被完全無(wú)法控制的第三方使用,那么怎么辦呢?也不是完全沒(méi)有辦法:

  • ·   去找頁(yè)面里的所有CSS規(guī)則,比如document.styleSheets。
  • ·   遍歷所有規(guī)則,把配置項(xiàng)中的headerClass、cellClass等拿出來(lái)。
  • ·   提取需要的幾個(gè)class中的所有樣式,再自己組裝成新的選擇器,如beautiful-table th。
  • ·   使用創(chuàng)建出來(lái)的選擇器,生成新的stylesheet,加入到DOM樹(shù)中。
  • ·   那么只給table加上beautiful-table這個(gè)class就搞定了。

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

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

***的補(bǔ)充

這篇文章,僅僅是想在jQuery的各個(gè)實(shí)現(xiàn)的層面上來(lái)進(jìn)行優(yōu)化,只涉及到了對(duì)jQuery整個(gè)運(yùn)行過(guò)程的分析、細(xì)節(jié)介紹和優(yōu)化方向,并沒(méi)有提到一些基本之基本的優(yōu)化方法,比如:

先將整個(gè)table從DOM樹(shù)中移除,完成所有的操作之后再放回DOM,減少repaint。

將mouseover和mouseout改為mouseenter和mouseleave,減少因?yàn)橄抡_的事件冒泡模型導(dǎo)致的重復(fù)的事件函數(shù)的執(zhí)行。

對(duì)于th、td之類單純?cè)氐倪x擇,優(yōu)先考慮使用原生的getElementsByTagName,消滅sizzle分析選擇器的時(shí)間。

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

原文地址:http://www.otakustay.com/jquery-code-optimization-1/

【編輯推薦】

  1. jQuery1.5的六大細(xì)節(jié)改進(jìn):DOM操作更簡(jiǎn)單
  2. jQuery入門:數(shù)組的三種類型三種操作
  3. JavaScript內(nèi)存回收機(jī)制深入解讀
責(zé)任編輯:陳貽新 來(lái)源: Gray Zhang的博客
相關(guān)推薦

2011-11-02 17:17:06

jQuery

2013-05-23 11:37:07

Windows SerWindows Ser

2012-04-26 13:12:09

jQuery代碼優(yōu)化

2022-07-14 14:46:51

數(shù)據(jù)庫(kù)SQL系統(tǒng)設(shè)計(jì)

2016-11-04 20:12:23

代碼應(yīng)用程序漏洞

2011-10-31 13:31:03

jQuery

2012-07-02 14:47:38

HTML5

2016-03-31 14:40:13

多云戰(zhàn)略多云計(jì)劃云模式

2010-10-17 14:30:20

業(yè)務(wù)分析與優(yōu)化云計(jì)算物聯(lián)網(wǎng)

2024-12-17 07:41:34

Java逃逸分析

2011-08-02 10:13:30

Java工具

2011-05-05 09:54:05

靜態(tài)代碼

2013-06-09 15:31:35

jQueryjQuery優(yōu)化性能優(yōu)化

2021-09-03 23:01:58

CSS 技巧代碼重構(gòu)

2011-08-03 16:51:01

jQuery

2014-04-23 16:43:05

Linux服務(wù)器性能分析

2010-03-30 14:17:30

CentOS操作系統(tǒng)

2010-10-17 02:16:20

業(yè)務(wù)分析與優(yōu)化IBM

2011-06-23 17:25:36

業(yè)務(wù)分析與優(yōu)化BAOWatson

2025-04-11 03:00:55

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)