引言
jQuery可以說是web開發領域應用最為廣泛的輕量級javascript庫,不僅專業的web開發者使用它,很多剛入門的web開發者或者web愛好者也通過使用jQuery輕鬆地融入到了javascript的開發。
而如果你還希望在這方面做得更好,就應學習和了解最佳實踐。最佳實踐(Best Practice)是隨某一技術領域的發展而逐漸建立起來的關於最新技術和開發方法的信息,在web開發領域也非常有用。
本文內容參考了傑出前端工程師Addy Osmani 的jQuery Performance TIPs & Tricks ,如果有興趣,你也可以自己看看這位大師的這個演說PPT,Addy Osmani本人也是jQuery的核心團隊(jQuery Core teams)的成員之一。
為什麼需要遵循jQuery最佳實踐
web開發領域對於效能的追求是永不停滯的。 jQuery雖然是非常強大的開發工具,但不當的使用方法仍會為瀏覽器帶來額外的工作和負擔,也會讓開發的web應用佔用更多的系統資源,運作起來也更慢。而我們都知道,好的web應用程式需要的是清爽靈活。
如何判斷javascript的效能呢?現在,這種效能測試都可以歸納為運行速度,簡單的說,同一項功能,某一種寫法如果比另一種寫法運行起來更快,那麼這種寫法就可以實現更好的性能。當然,這裡只單純從效能角度來考慮,不包含程式碼的可維護性。如果你想自己測試不同的javascript程式碼段的效能,推薦使用 jsPerf.com ,這個網站可以幫助你輕鬆建立javascript效能測試案例,還可以儲存和分享測試結果。 jQuery團隊也使用它進行javascript效能測試。
jQuery使用建議
1.使用最新版
新版的jQuery提供的API會在效能上有所提升,而且修正了一些存在的bug。由於非常多的網站都在使用jQuery,所以jQuery每個新版本的變更都會經過非常嚴格的測試,升級一般都不會帶來問題。
此外,新版的jQuery可能會在API上做非常有用的改動,讓開發工作更簡單。例如在jQuery 1.7之前,事件綁定使用bind()、delegate()以及live()這幾個方法。雖然都是事件綁定,但每個方法各有針對,這就產生了「什麼時候該使用哪一個」的麻煩事。而從jQuery 1.7開始,新增並推薦使用on()和off()這2個方法來完成所有的事件綁定與移除,理解起來就要容易多了。
2.理解你的選擇子
在jQuery中,不是所有的選擇符(Selectors)都是同等性能的。也就是說,雖然某一些元素你可以用很多不同的選擇符寫法來選取,但不要認為它們在效能上也是一樣的。
jQuery的選擇符的運行速度是不同的,從最快到最慢依序是:
由於瀏覽器支援的原生DOM操作方法(例如document.getElementById())就可用,所以ID選擇符和元素選擇符是最快的。而稍慢的Class選擇符是因為IE6-IE8不支援原生的getElementsByClassName(),而在支援這個原生方法的其他現代瀏覽器中,Class選擇符仍是很快的。
至於最慢的偽類和屬性選擇符,則是因為瀏覽器並沒有提供對應功能的可用原生方法。雖然jQuery嘗試了使用querySelector()和querySelectorAll()這兩個原生選擇符API(屬於css查詢API)來提升部分jQuery選擇符在部分現代瀏覽器中的性能,但綜合起來,仍然是比較慢的。當然,這也是在於jQuery對偽類別和屬性選擇符這個API要求較高,不僅要支援input[type="text"]這種css中合法的選擇符,還要支援p:first這類用於元素過濾,但在css中不合法的選擇符。總之,jQuery的偽類和屬性選擇符功能很強大,但請慎重使用。
3.快取你操作的元素
var parents = $('.parents'); var children = $('.parents').find('.child'); //bad
快取是指保存jQuery選擇符的回傳結果,方便之後再呼叫。每一個$('.whatever')都會重新從DOM搜尋並傳回一個jQuery包裝集(jQuery collection),因此要避免重複使用。
原生javascript中,建立局部變數來快取資料或對象,有利於精簡程式碼、最佳化效能。這裡也是一樣的道理。
4.鍊式語法
var parents = $('.parents').doSomething().doSomethingElse();
jQuery中大部分方法都返回jQuery包装集并支持这种链式语法。javasript的性能优化要点之一是最小化语句数,因此链式语法不仅写起来更容易,运行起来也会更快。
5.使用事件代理
利用事件冒泡,指定一个位于dom较高层级的元素(比如document)的事件处理程序,就可以管理某一类型的所有事件。减少了页面中添加的事件处理程序,自然可以提升整体性能。
6.最小化现场更新
如果你进行操作的DOM部分是已经显示的页面的一部分,那么你就是在进行一个现场更新。现场更新需要浏览器重新计算尺寸,涉及到重绘(repaint)和回流(reflow),有较高的性能花费,因此应减少使用。
在新增内容时,建议先把要新增的代码段合并完全,最后再使用单个append()方法添加到页面。而如果元素存在复杂的交互,比如反复地添加和移除,detach()这个针对性的方法就是最佳的选择。
7.不在不必要的时候使用jQuery方法
$('.nav_link').bind('click', function() { console.log('nav id: ' + $(this).attr('id')); //bad
$.data(elem, key, value); //significantly faster
};
jQuery方法不一定是最好的方法。这里使用$(this).attr('id')获取当前事件元素的ID,为当前事件元素创建了jQuery包装集,然后调用attr()属性获取方法。但这都是额外的性能花费。事实上,this在事件函数内就表示当前事件元素,直接使用this.id就可以获取元素ID,这种原生DOM属性的写法要更快。
8.适当使用jQuery工具函数
操作jQuery包装集的方法(也就是写在$.fn中的方法),其中一部分也有作为jQuery工具函数(直接写在$中的方法)的同类方法。由于jQuery工具函数在使用中不涉及创建jQuery包装集,因此,在部分情况下,可以通过换用jQuery工具函数提升性能。
比如,在DOM中存储数据,一般的做法是:
$('#elem').data(key, value); //common way
但改为下边的写法会快很多:
需要的注意的是,虽然下面这种方法更快,但作为参数传入的元素不能用选择符,而要用元素本身。
结语
我自己整理和写本文内容时,也感觉很有收获。jQuery是一个很强大的工具,但进一步说,也只提供了web开发的最基本的内容,更高级更复杂的内容,还需要自己不断学习和创作。在这个过程中,遵循最佳实践,养成良好的习惯,会有很大的益处,并逐渐做得更出色!