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

时间:2022-10-18 00:04:01

I am writing a jQuery plugin and I am at the optimization stage.

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

I wonder which of these leads to a quicker script in general, and what sort of mitigating factors are important:

我想知道哪些导致更快的脚本,以及哪种缓解因素很重要:

  1. Have the script generate lots of classes and ids at the start so finding elements in the dom is easier (quicker too?) later on.
  2. 让脚本在开始时生成许多类和ID,以便稍后在dom中查找元素更容易(更快)?

  3. Keep classes and ids to a minimum (so save time by not creating them), but then look for elements in more convoluted ways later (eg the nth item in an object), which I presume is slower than getting by id/class.
  4. 将类和ID保持在最小值(这样可以通过不创建它们来节省时间),但之后会以更复杂的方式查找元素(例如,对象中的第n个项),我认为这比通过id / class获取要慢。

4 个解决方案

#1


The question is not really specific enough so I can give you advice directly relevant to your code, but here are some of my favorite jQuery optimization tips:

问题不够具体,所以我可以给你直接与你的代码相关的建议,但这里有一些我最喜欢的jQuery优化技巧:

  1. Whenever possible, specify a context! Don't make jQuery look places it doesn't have to. If you know that something is going to be inside the #container div, then do $(something, '#container');
  2. 只要有可能,请指定上下文!不要让jQuery看起来不必要的地方。如果你知道#container div里面会有东西,那就做$(某事,'#container');

  3. .myclass is slow. Internally, jQuery has to go through every single element to see if it has the class you are searching for, at least for those browsers not supporting getElementsByClassName. If you know that a class will only be applied to a certain element, it is way faster to do tag.myclass, as jQuery can then use the native getElementsByTagName and only search through those.
  4. .myclass很慢。在内部,jQuery必须遍历每个元素以查看它是否具有您要搜索的类,至少对于那些不支持getElementsByClassName的浏览器而言。如果你知道一个类只会应用于某个元素,那么执行tag.myclass会更快,因为jQuery可以使用本机getElementsByTagName并只搜索那些。

  5. Don't do complicated selectors in one bang. Sure, jQuery can figure out what you want, but it takes time to parse out the string and apply the logic you want to it. As such, I always like to separate my "queries" out into patches. While most people might do $('#myform input:eq(2)'); or something like that, I prefer to do $('input','#myform').eq(2); to help jQuery out.
  6. 不要在一次爆炸中做复杂的选择器。当然,jQuery可以找出你想要的东西,但是需要时间来解析字符串并应用你想要的逻辑。因此,我总是喜欢把我的“查询”分成补丁。虽然大多数人可能会做$('#myform输入:eq(2)');或类似的东西,我更喜欢做$('输入','#myform')。eq(2);帮助jQuery。

  7. Don't re-query the DOM if you plan on doing multiple things with a set of objects. Take advantange of chaining, and if not possible to use chaining for whatever reason, cache the results of the query into a variable and perform your calls on that.
  8. 如果您计划使用一组对象执行多项操作,请不要重新查询DOM。利用链接的优势,如果由于某种原因无法使用链接,请将查询结果缓存到变量中并对其执行调用。

#2


The way the browser works is that upon load it creates an in-memory DOM tree which looks as follows:

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

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

So when you lookup P > DIV > B, the lookup has to find all P elements, then find all DIV elements within P and then find all B elements within DIV. The deeper the nesting the more lookups it needs to do. Further, it might find all P > DIV only to find that none of them have B and it will have wasted time looking through all P > DIV matches.

因此,当您查找P> DIV> B时,查找必须找到所有P元素,然后查找P中的所有DIV元素,然后查找DIV中的所有B元素。嵌套越深,它需要执行的查找越多。此外,它可能会发现所有P> DIV只发现它们都没有B并且它将浪费时间查看所有P> DIV匹配。

Lookups by ID are faster because IDs are guaranteed to be unique so the DOM can store them as hash table entries which have very fast lookups. In terms of jQuery the implementation might be slightly different, however, document.getElementById has the fastest lookup time so $('#my_node_id') should also be quite fast.

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

Consequently, if your node doesn't have an ID, you can find the nearest ancestor that does and find your node relative to that ancestor

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

#my_node_id > div > b

because the look up only needs to happen under the sub-tree of #my_node_id it will be faster than p > div > b

因为查找只需要在#my_node_id的子树下进行,它会比p> div> b更快

#3


I think you answered your own question: 'convoluted ways' is a synonym for 'it will break' - any changes to the html structure will break your code.

我认为你回答了自己的问题:'复杂的方式'是'它会破坏'的同义词 - 对html结构的任何更改都会破坏你的代码。

For example, imagine you're trying to get myDiv and you assume it's the last sibling of child:

例如,假设您正在尝试获取myDiv并且您认为它是孩子的​​最后一个兄弟:

<div>parent
     <div>child</div>
     <div>myDiv</div>
</div>

What happens if you later decide the structure should really be like this?

如果你以后决定结构应该是这样的话会发生什么?

<div>parent
     <div>child</div>
     <div>myDiv</div>
     <div>child</div>
</div>

By relying on assumptions about structure your code becomes really brittle. Adding classes and ids to nodes will prevent such scenarios.

通过依赖关于结构的假设,您的代码变得非常脆弱。向节点添加类和ID将防止此类情况。

I think you should go with the first choice. Do also remember that getting nodes by class is always slower than getting them by id.

我认为你应该选择第一选择。还要记住,按类获取节点总是慢于通过id获取节点。

#4


With my plugins I try, as best I can, to limit the amount of hooks I introduce into the document. By "hooks" I mean IDs or classes.

使用我的插件,我尽可能地尝试限制我在文档中引入的钩子数量。 “钩子”是指ID或类。

The best way to avoid them completely is to retain references to any created elements within your plugin's closure. For example:

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

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!');
});

The list can be carried around JavaScript functions (referenced and used in multiple places) without requiring any hooks in the HTML; thus making it as unobtrusive as possible!

该列表可以围绕JavaScript函数(在多个地方引用和使用)进行,而不需要HTML中的任何钩子;从而使它尽可能不引人注目!

Avoiding/limiting hooks is especially important in plugin development because you never know where it might end up being used.

避免/限制挂钩在插件开发中尤其重要,因为您永远不知道最终可能会在何处使用它。

#1


The question is not really specific enough so I can give you advice directly relevant to your code, but here are some of my favorite jQuery optimization tips:

问题不够具体,所以我可以给你直接与你的代码相关的建议,但这里有一些我最喜欢的jQuery优化技巧:

  1. Whenever possible, specify a context! Don't make jQuery look places it doesn't have to. If you know that something is going to be inside the #container div, then do $(something, '#container');
  2. 只要有可能,请指定上下文!不要让jQuery看起来不必要的地方。如果你知道#container div里面会有东西,那就做$(某事,'#container');

  3. .myclass is slow. Internally, jQuery has to go through every single element to see if it has the class you are searching for, at least for those browsers not supporting getElementsByClassName. If you know that a class will only be applied to a certain element, it is way faster to do tag.myclass, as jQuery can then use the native getElementsByTagName and only search through those.
  4. .myclass很慢。在内部,jQuery必须遍历每个元素以查看它是否具有您要搜索的类,至少对于那些不支持getElementsByClassName的浏览器而言。如果你知道一个类只会应用于某个元素,那么执行tag.myclass会更快,因为jQuery可以使用本机getElementsByTagName并只搜索那些。

  5. Don't do complicated selectors in one bang. Sure, jQuery can figure out what you want, but it takes time to parse out the string and apply the logic you want to it. As such, I always like to separate my "queries" out into patches. While most people might do $('#myform input:eq(2)'); or something like that, I prefer to do $('input','#myform').eq(2); to help jQuery out.
  6. 不要在一次爆炸中做复杂的选择器。当然,jQuery可以找出你想要的东西,但是需要时间来解析字符串并应用你想要的逻辑。因此,我总是喜欢把我的“查询”分成补丁。虽然大多数人可能会做$('#myform输入:eq(2)');或类似的东西,我更喜欢做$('输入','#myform')。eq(2);帮助jQuery。

  7. Don't re-query the DOM if you plan on doing multiple things with a set of objects. Take advantange of chaining, and if not possible to use chaining for whatever reason, cache the results of the query into a variable and perform your calls on that.
  8. 如果您计划使用一组对象执行多项操作,请不要重新查询DOM。利用链接的优势,如果由于某种原因无法使用链接,请将查询结果缓存到变量中并对其执行调用。

#2


The way the browser works is that upon load it creates an in-memory DOM tree which looks as follows:

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

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

So when you lookup P > DIV > B, the lookup has to find all P elements, then find all DIV elements within P and then find all B elements within DIV. The deeper the nesting the more lookups it needs to do. Further, it might find all P > DIV only to find that none of them have B and it will have wasted time looking through all P > DIV matches.

因此,当您查找P> DIV> B时,查找必须找到所有P元素,然后查找P中的所有DIV元素,然后查找DIV中的所有B元素。嵌套越深,它需要执行的查找越多。此外,它可能会发现所有P> DIV只发现它们都没有B并且它将浪费时间查看所有P> DIV匹配。

Lookups by ID are faster because IDs are guaranteed to be unique so the DOM can store them as hash table entries which have very fast lookups. In terms of jQuery the implementation might be slightly different, however, document.getElementById has the fastest lookup time so $('#my_node_id') should also be quite fast.

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

Consequently, if your node doesn't have an ID, you can find the nearest ancestor that does and find your node relative to that ancestor

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

#my_node_id > div > b

because the look up only needs to happen under the sub-tree of #my_node_id it will be faster than p > div > b

因为查找只需要在#my_node_id的子树下进行,它会比p> div> b更快

#3


I think you answered your own question: 'convoluted ways' is a synonym for 'it will break' - any changes to the html structure will break your code.

我认为你回答了自己的问题:'复杂的方式'是'它会破坏'的同义词 - 对html结构的任何更改都会破坏你的代码。

For example, imagine you're trying to get myDiv and you assume it's the last sibling of child:

例如,假设您正在尝试获取myDiv并且您认为它是孩子的​​最后一个兄弟:

<div>parent
     <div>child</div>
     <div>myDiv</div>
</div>

What happens if you later decide the structure should really be like this?

如果你以后决定结构应该是这样的话会发生什么?

<div>parent
     <div>child</div>
     <div>myDiv</div>
     <div>child</div>
</div>

By relying on assumptions about structure your code becomes really brittle. Adding classes and ids to nodes will prevent such scenarios.

通过依赖关于结构的假设,您的代码变得非常脆弱。向节点添加类和ID将防止此类情况。

I think you should go with the first choice. Do also remember that getting nodes by class is always slower than getting them by id.

我认为你应该选择第一选择。还要记住,按类获取节点总是慢于通过id获取节点。

#4


With my plugins I try, as best I can, to limit the amount of hooks I introduce into the document. By "hooks" I mean IDs or classes.

使用我的插件,我尽可能地尝试限制我在文档中引入的钩子数量。 “钩子”是指ID或类。

The best way to avoid them completely is to retain references to any created elements within your plugin's closure. For example:

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

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!');
});

The list can be carried around JavaScript functions (referenced and used in multiple places) without requiring any hooks in the HTML; thus making it as unobtrusive as possible!

该列表可以围绕JavaScript函数(在多个地方引用和使用)进行,而不需要HTML中的任何钩子;从而使它尽可能不引人注目!

Avoiding/limiting hooks is especially important in plugin development because you never know where it might end up being used.

避免/限制挂钩在插件开发中尤其重要,因为您永远不知道最终可能会在何处使用它。