jQuery中访问DOM元素的最有效方式是什么?

4

我正在编写一个 jQuery 插件,现在处于优化阶段。

我想知道哪种方式通常能够使脚本更快,并且有哪些重要的缓解因素:

  1. 在开始时生成大量类和 ID,使在后面查找 dom 元素更容易(也更快?)。
  2. 尽量减少类和 ID(不创建它们可以节省时间),但是随后以更复杂的方式查找元素(例如,对象中的第 n 项),我认为这比获取 id/class 更慢。
4个回答

12

浏览器的工作方式是,在加载时创建一个内存中的DOM树,其形式如下:

                                              P
                               _______________|______________
                              |                              |
                          childNodes                    attributes
                ______________|___________                   |
               |              |           |            title = 'Test paragraph'
         'Sample of text '   DIV   'in your document'
                              |
                          childNodes
                    __________|_______
                   |          |       |
           'HTML you might'   B     'have'

如果你查找的是 P > DIV > B,那么这个查找过程需要先找到所有的 P 元素,然后在这些 P 元素中查找所有的 DIV 元素,最后再在这些 DIV 元素中查找所有的 B 元素。嵌套层次越深,需要进行的查找就越多。此外,它可能会查找所有的 P > DIV,只发现没有任何一个匹配元素拥有 B,从而浪费时间。

通过 ID 进行查找更快,因为 ID 是唯一的,所以 DOM 可以将它们存储为哈希表条目,这样就可以非常快速地进行查找。就 jQuery 而言,实现可能略有不同,但是 document.getElementById 具有最快的查找时间,因此 $('#my_node_id') 也应该很快。

因此,如果你的节点没有 ID,你可以找到最近的具有 ID 的祖先节点,并相对于该祖先节点查找你的节点。

#my_node_id > div > b

因为查找只需要在 #my_node_id 子树下发生,所以它比 p > div > b 更快。


11

这个问题不是非常具体,所以我无法直接给出与您的代码直接相关的建议,但以下是一些我最喜爱的jQuery优化技巧:

  1. 尽可能指定上下文!不要让jQuery去寻找它不必要的地方。如果您知道某些内容将在#container div内,则执行$(something, '#container');
  2. .myclass速度较慢。在没有支持getElementsByClassName的浏览器中,内部会遍历每个单独的元素以查看它是否具有您正在搜索的类。如果您知道类只会应用于特定元素,则使用tag.myclass速度更快,因为jQuery可以使用本地getElementsByTagName并仅在其中搜索。
  3. 不要一次性进行复杂的选择器操作。当然,jQuery可以找出你想要的,但解析字符串并应用你想要的逻辑需要时间。因此,我总是喜欢将我的“查询”分成修补程序。虽然大多数人可能会执行$('#myform input:eq(2)');或类似的操作,但我更喜欢执行$('input','#myform').eq(2);来帮助jQuery。
  4. 如果您计划对一组对象执行多个操作,请不要重新查询DOM。利用链接,并且如果由于某种原因无法使用链接,则将查询结果缓存到变量中,然后对其执行调用。

5
我认为你已经回答了自己的问题:“复杂的方式”是“代码将会出错”的同义词 - 对于HTML结构的任何更改都会破坏你的代码。
例如,假设你正在尝试获取myDiv并且你假设它是child的最后一个兄弟节点:
<div>parent
     <div>child</div>
     <div>myDiv</div>
</div>

如果您后来决定结构应该是这样的,会发生什么?
<div>parent
     <div>child</div>
     <div>myDiv</div>
     <div>child</div>
</div>

如果你的代码依赖于对结构的假设,那么它会变得非常脆弱。给节点添加类和id将防止出现这种情况。

我认为你应该选择第一种方法。同时请记住,通过类获取节点总是比通过id获取节点慢。


3

我尽可能地减少插件引入文档的钩子数量。所谓“钩子”,指的是ID或类。

完全避免它们的最佳方法是在插件闭包内保留对任何创建元素的引用。例如:

jQuery.fn.addList = function(items, fn){
    var $list = $('<ul/>').html('<li>' + items.join('</li><li>') + '</li>');
    return this.each(function(){
        $(this).append($list);
        fn.call($list);
    });
};

$('body').addList(['item 1', 'item 2'], function(){
    var referenceToTheList = this;
    console.log(referenceToTheList, '<- this is my list, no hooks involved!');
});
  • 该列表可以在JavaScript函数中传递(被引用和多次使用),而不需要在HTML中添加任何钩子;因此尽可能地使其不显眼!
  • 在插件开发中,避免/限制钩子尤为重要,因为您永远不知道它可能会在哪里使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接