前面运行的 jQuery 性能测试结果支持这一数据。让我们查看每个测试,看看需要注意 jQuery 代码的什么地方。在这个例子中,分别看看通过 ID 和 CLASS 进行搜索时的测试结果(图 5)。
图 5. ID 搜索和 CLASS 搜索对比这些测试是不同的,但它们得出的数据表明通过 ID 进行搜索比通过 CLASS 进行搜索快得多。这如何影响到 jQuery 代码?在编写搜索时,您要记住这些技巧:如果既可选择 CLASS 又可选择 ID,那么通常要选择 ID。如果需要在您的代码中搜索某些元素,一定要给它们分配 ID。
清单 1 显示了一个实际的 jQuery 测试,您可以在您的机器上运行它对此进行验证:
清单 1. CLASS 和 ID$(document).ready(function() { console.info("Start Test"); var d = new Date(); console.info(d.getSeconds() + " " + d.getMilliseconds()); var testBody = ""; for (var i=0; i<1000; i++) { testBody += "<div>"; } $("body").append(testBody); for (var i=0; i<1000; i++) { $(".testable"+i); } var d = new Date(); console.info(d.getSeconds() + " " + d.getMilliseconds()); console.time("Start ID Test"); testBody = ""; for (var i=0; i<1000; i++) { testBody += "<div>"; } $("body").append(testBody); for (var i=0; i<1000; i++) { $("#testable"+i); } var d = new Date(); console.info(d.getSeconds() + " " + d.getMilliseconds()); console.info("End Test"); });
ID 测试耗时 218 毫秒,而 CLASS 测试耗时 19.9 秒!甚至在专门为该测试构建的简单页面上,ID 搜索也要比 CLASS 搜索快 100 倍!
技巧 #2 - 提供尽可能多的搜索信息
jQuery 提供如此多的页面元素搜索方法,有时您难以指出哪种方法是最好的。有一条经验是不会错的,即为搜索参数提供尽可能多的信息。因此,假如您正在搜索带有 “clickable” CLASS 的所有页面元素,如果您提前知道仅有 DIV 附带有 CLASS,那么就能提高搜索性能。所以,搜索 “div.clickable” 会更加快。图 6 显示了支持该技巧的结果。
考虑到底层 JavaScript 代码之后,这就不足为奇了。通过提供元素标记,与 CLASS 参数匹配的搜索元素数量将大大减少,从而将搜索性能提升至与本例中的 ID 搜索相当。
开发人员在编写 jQuery 选择方法时不能偷懒,尽管 jQuery 的简单让人产生偷懒的欲望。简单让您放松了警惕。搜索机制变得如此简单,让我们倾向于仅输入一条信息。然而,您应该总是尽可能多地输入信息,尤其是已知信息。清单 2 显示了一个很好的例子。
清单 2. 提供充足的信息// Assume there are 50 of these in some giant form, and you need to validate // these fields before they are submitted, and there are hundreds of other // elements on the page as well <input type=text> // the "bad" way to validate these fields $(".notBlank").each(function(){ if ($(this).val()=="") $(this).addClass("error"); }); // the "good" way to validate these fields $("input.notBlank").each(function(){ if ($(this).val()=="") $(this).addClass("error"); }); // the "best" way to validate these fields $("input:text.notBlank").each(function(){ if ($(this).val()=="") $(this).addClass("error"); });
技巧 #3 - 缓存选择器
最后一个性能技巧利用了几乎所有 jQuery 选择器都返回 jQuery 对象这个特性。这意味着在理想的情况下,您仅需要运行选择器一次,并且能够轻松地将所有函数连接在一起,或缓存结果供以后使用。您也不要担心缓存,因为与总体可用内存相比,返回的对象是很小的。
清单 3 给出了一些关于如何利用缓存的例子。
清单 3. 缓存// Imagine a function that hides all the div's with a class of "hideable" // when a button is pressed. These DIV's might reappear later when // working with the page, so the button can be pressed any number of // times, and the DIV's that have reappeared // will again be made to be hidden. $("#ourHideButton").click(function(){ $(".hideable").hide(); }); // As you saw in the CLASS versus ID example, though, a search for // CLASS is very inefficient // If this button is pressed often, it could lead to a slow response // Instead of the above example, you should write your code like this var hideable; $("#ourHideButton").click(function(){ if (hideable) hideable.hide(); else hideable = $(".hideable").hide(); }); // You can cache your search in a JavaScript variable and reuse it every time // the button is pressed. Because jQuery almost always returns the // jQuery object, you can save it the first time it is called for future use
在我的最后一个关于性能的示例代码中,将查看我在本系列的第一篇文章中提到的小部件(见 )。这个小部件是在表的左上角上的复选框,它允许您选择或取消选择该列上的所有复选框。这个小部件在电子邮件应用程序中非常常见,用于选择或取消选择所有消息。
清单 4. 性能改进// Here is the code as I originally presented it in that article. Let's see // if we can improve the performance in any way from the things we learned here function selectAll() { var checked = $("#selectall").attr("checked"); $(".selectable").each(function(){ var subChecked = $(this).attr("checked"); if (subChecked != checked) $(this).click(); }); } // Here's the improved function. The search for the ID of "selectall" is // OK as-is, because we saw how fast the ID search is. // The search for the CLASS of "selectable" was not well-designed though, // because we saw a search by CLASS is very inefficient. // First step was improving the search by supplying as much information as we know. // We narrowed the search to only checkboxes with the CLASS of selectable. // This should improve our search // Further, we can cache this search because we will only need to perform it once // Finally, we can perform this search before the selectall checkbox is even // checked (when the page is finished loading), so that the search is completed // and cached before the user even uses it. // These 3 simple performance steps gave me a 200% increase in speed when tested // on a page with 200 rows of data. var selectable = $(":checkbox.selectable"); function selectAll() { var checked = $("#selectall").attr("checked"); selectable.each(function(){ var subChecked = $(this).attr("checked"); if (subChecked != checked) $(this).click(); }); }
关于性能的要点