14

我在我的 JSP 中多次使用这个 jQuery 选择器:

 $("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']")

我在一些博客上找到的解决方案是我应该先做:

var customer=$('#customers')

然后使用上面的客户对象进行进一步的调用。

 customer.find("tbody tr td input[type='checkbox'][name='selectedCustomers']")

我的问题是,这个解决方案会有什么不同吗?为什么?

我的理解

当我做

$("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']")

jQuery 内部会先获取关联的对象div id="customers" (通过 document.getElementById("customers")),然后会遍历到指定的 checkbox. 如果我按照建议的解决方案进行,那么document.getElementById("customers")只会被解雇一次,其余的都是一样的。所以我把自己从不必要的多重中拯救出来,document.getElementById但其余的都是一样的。我的理解正确吗?如果是的话,就我所知,是document.getElementById更昂贵的操作吗?

编辑:-

我不仅多次使用上述选择器,而且还在 div id="customer" 下使用其他可能的选择器。那么问题来了,如果我先缓存客户对象,如果我不这样做,性能方面有什么区别?

4

4 回答 4

6

没有办法你需要那么具体。我猜,最多是这样的:

$('#customers td [name="selectedCustomers"]')

...这应该可以提高性能。接下来,如果您实际上selectedCustomers每次都在查询,则应该缓存整个内容:

var selectedCustomers = $('#customers td [name="selectedCustomers"]');

否则,如果名称是动态的,并且每页只有一个具有相同名称的项目...

var item = $(document.getElementsByName(someName)[0]);

$('#customers')另一方面,缓存只是毫无意义。.findoncustomers将首先完成与整个选择器一样多的工作,尤其是在querySelector支持的情况下。

于 2012-12-22T15:21:40.100 回答
3

您似乎错过了缓存对象的基本点。一旦对象被缓存,该选择器中的任何进一步遍历或操作都将在存储的对象上执行,并且不需要搜索 DOM 来首先定位选择器并在每次需要使用它时创建集合

每次调用时$("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']")都必须执行文档搜索以创建元素集合,然后才能对集合进行任何更改。

缓存集合意味着无需进行进一步搜索,从而提高性能

/* locate and store the collection once*/
var $checkboxes=$("#customers tbody input[name='selectedCustomers']");
/* look within previously stored collection*/
$checkboxes.filter(/* expression*/ ).doSomething();

使用document.getElementById将比 jQuery 搜索更快,仅仅是因为它不需要 jQuery 库进行的附加函数调用。但是,如果您希望将 result 用作 jQuery 对象,例如: $( document.getElementById('foo')) 对于单次使用缓存对象,收益可能不值得担心

于 2012-12-22T15:25:56.920 回答
1

所以我把自己从不必要的多重中拯救出来,document.getElementById但其余的都是一样的。

是的。但也可能不是,因为选择器是从右到左评估的(参见这篇文章这个 SO 问题)。假设一个高效的引擎,如果它只对文档树的一部分进行评估(如果您先选择#customers然后.find()在其中进行评估),那么它要做的工作就会更少。但我对此不是 100% 确定的。

document.getElementById不是更昂贵的操作?

不,它非常便宜。id 是识别单个元素的标准属性,浏览器会为它构建非常高效的查找表——你可以假设它几乎是O(1).

customer.find("tbody tr td input[type='checkbox'][name='selectedCustomers']")

另一方面,需要评估 DOM 树的 DOM 选择器查询非常昂贵,特别是如果在 JS 代码(jQuery sizzle)中手动完成而不是原生的 - 尽管这个相当简单的查询委托给原生的querySelectorAll.

我猜那#customers是你的表格元素。因此,为了性能,省略tbody tr td标签,它们是强制性的(假设您没有使用它们明确地从<thead>/<tfoot><th>元素中排除复选框)。无论如何,您不会找到<input>作为表格元素的直接子元素的 - 并且选择器引擎要做的事情要少得多。

此外,如果您非常了解您的标记并且可以假设只有复选框具有该name属性,那么您也可以省略标记名和类型属性选择器。这意味着您可以委托给 native getElementsByName,这应该会再次提高性能:

$(document.getElementById("customers").getElementsByName("selectedCustomers"))

如果您需要检查元素是否为复选框,您仍然可以过滤它们。有了这个,你最终可能会得到

$(customer.get(0).getElementsByName("selectedCustomers")).filter(":checkbox")

但是,为了证明性能提升,您只能测试、测试、测试;您需要在实际的整页上执行此操作。

于 2012-12-22T20:09:11.213 回答
0

http://jsperf.com/different-jquery-selector-tests

看看这个小测试。基本上$('#div').find('#p'); 是最快的$('div').find('#p'); 是最慢的。

于 2014-10-21T21:06:51.773 回答