将选定/找到的元素存储在变量中会提高性能吗?

Posted

技术标签:

【中文标题】将选定/找到的元素存储在变量中会提高性能吗?【英文标题】:Does storing selected/found elements in variable increase performance? 【发布时间】:2012-05-16 09:36:25 【问题描述】:

我创建了一个 jQuery 插件来修改我的导航。不幸的是,我必须访问和修改几乎所有子元素,例如<ul><li><a> 等等。然后需要这些元素一到四次。

我应该将它们全部存储在变量中,还是应该在需要时像 $('.my-nav').find('li')$('.my-nav').find('li') 一样访问它们?

为 25 行代码设置 5 个变量似乎很浪费内存。 但我不知道这是否是一个可以接受的权衡以获得更高的性能。

我创建了一个 Fiddle 来说明其含义:http://jsfiddle.net/Yj35Q/2/

【问题讨论】:

谢谢,我更正了小提琴。 【参考方案1】:

无论你是否使用 jQuery,在适当的地方缓存你的 DOM 元素当然是明智的。

但是这个问题让我想到也许我们应该有一个插件来帮助解决这个问题。找了一圈也没找到。

所以我很快就写了一篇。这是lazy loading jQuery selector...

(function($)
    var cachedObjects = new Array();

    $.lazy = function(selector) 
        if (typeof selector != "string" || arguments.length > 1) 
            return $.apply(this, arguments);

        var o = cachedObjects[selector];
        if (o == undefined)
        
            o = $(selector);
            cachedObjects[selector] = o;
        

        return o;
    ;
)(jQuery);

你会这样使用它...

$.lazy('.my-nav').show();

如果我忽略了什么,请告诉我。但我相信,只要您选择的元素是静态的并且永远不会动态添加或删除,那么使用它会很好。

更新

我已更改代码以提高效率。 And I've added a line to return $(selector) when the selector is not a string.所以缓存只有在选择器是字符串时才会起作用。

更新 #2

现在根据 jfriend00 的建议,当您不只是传递字符串时,它会是 return $.apply(this, arguments)

【讨论】:

一个有趣的想法。所以,不是$(selector).fadeOut(),而是使用$.lazy(selector).fadeOut()。我建议您确保选择器是一个字符串,并且当它没有被缓存时它可能会更有效,因为您只需将其放入cachedObjects 之后就不必再次查找它。 @jfriend00 - 好主意。我将在今晚晚些时候进行这些更改。 我想我会称它为$.cache$cache 或代表它正在使用缓存的事实。 $.lazy 不适合我。您可能也希望能够清除缓存。 我不同意延迟加载。这根本不是延迟加载。只要您进行函数调用,它就会解析选择器,而不是稍后。相对于提前获取它们可能是懒惰的,但对于你的函数的用户来说,没有什么懒惰的。如果直到稍后调用方法时才完全解析选择器,那将是懒惰的。那会很懒惰。这只是在请求时解析选择器并将其放入缓存中。 我不同意。您所做的事情并没有什么懒惰,您的函数的用户也不会认为它是懒惰的。它在调用时立即 评估选择器,然后缓存结果以供将来的请求使用。只有在函数调用之后的某个时候才评估选择器,例如当一个方法真正想要对其进行操作时,它才会是惰性的。【参考方案2】:

在同一个函数中,我会将 DOM 搜索的结果缓存在一个局部变量中,这样我就不必在同一个函数中多次执行同一个 DOM 搜索。对于大多数函数来说,这不是必需的,但是仅在函数执行期间将结果放入局部变量中既简单又安全,所以我认为这是一个好习惯。

我通常不会将 DOM 节点缓存到全局变量中,因为我尽量避免使用全局变量,而且在需要特定功能时检索 DOM 节点很少会成为性能问题。避免在全局变量中使用 DOM 引用的另一个原因是,如果从 DOM 中删除了特定的 DOM 节点并且您打算对其进行垃圾回收,如果全局变量中有对它的引用,则 DOM 节点将不会被垃圾收集并可能导致内存泄漏。

在某些情况下,我会反复查找同一个 DOM 节点(例如在计时器上),我会将 DOM 节点缓存到函数闭包中的非全局变量中,然后在本地使用该变量。但是,我发现这种情况很少见。

【讨论】:

+1。让我知道你对我的延迟加载 jQuery 选择器的看法。 非常感谢您的回答。通常,我想接受多个答案,但不幸的是只能接受一个。 fritzfromlondon 快一点。 @JohnB。 - fritzfromlondon 的答案和我的答案是不同的答案,有不同的建议。我认为你会投票给对你来说更有意义或看起来更完整的那个,而不是比另一个早几分钟出现的那个。我不反对你选择与我不同的答案,只是当答案不同时,你的标准不应该是哪个先出现。 @jfriend00 你是对的,你的答案都不同,但我一直在寻找的底线(我应该缓存还是不缓存)都得到了双方的回答。你有关于范围的有价值的信息,他是一个很好的测试用例的链接。但我可以看到,我的“稍微快一点”对我申请选择答案的标准产生了错误的印象。【参考方案3】:

缓存节点总是好的做法。您还可以使用http://jsperf.com/ 对自己进行基准测试

除非您要存储大量的 DOM 树或其他东西,否则您实际上不需要担心变量需要多少存储空间。与 JS 引擎定位节点所需的工作量更相关。

编辑 甚至更好的是,您可以找到其他人已经创建的现有测试用例http://jsperf.com/ns-jq-cached/4

【讨论】:

以上是关于将选定/找到的元素存储在变量中会提高性能吗?的主要内容,如果未能解决你的问题,请参考以下文章

优化程序性能——提高并行性

将 $('body, html') 选择存储为 jQuery

jQuery 在附加到 DOM 之前从元素中生成变量

如何提高 dataadapter.fill 的性能?

nginx开发读变量

Vue 计算属性