使用下划线memoize缓存jquery选择器结果

使用下划线memoize缓存jquery选择器结果,jquery,caching,underscore.js,Jquery,Caching,Underscore.js,我正在寻找优化我的单页应用程序的方法,目前我主要关注jQuery选择器 我不是javascript专家,但据我所知,将jquery选择器的结果存储在变量中以供重用要比重新查询dom性能好得多 因此,例如,与此相反: $("#myItem").doSomething(); $("#myItem").doSomethingElse(); 这样做更有意义: var result = $("#myItem"); result.doSomething(); result.doSomethingElse(

我正在寻找优化我的单页应用程序的方法,目前我主要关注jQuery选择器

我不是javascript专家,但据我所知,将jquery选择器的结果存储在变量中以供重用要比重新查询dom性能好得多

因此,例如,与此相反:

$("#myItem").doSomething();
$("#myItem").doSomethingElse();
这样做更有意义:

var result = $("#myItem");
result.doSomething();
result.doSomethingElse();
var myapp={};
myapp.$body=$(document.body);
myapp.$result = myapp.$body.find("#myItem").doSomething().doSomethingElse();
myapp.$result.find("> .whatever")
另外,据我所知,使用附加到现有jQuery对象的find()选择器可以极大地提高性能,从而减少必要的查询量:

$("#myItem").find(".highlighted");
我感兴趣的是探索存储我们在应用程序中不断重用的许多选择器的可能性,不仅仅是存储在局部变量中,还可能存储在某个地方的散列或外部函数中。我不知道这是否是最佳的,但我很好奇这会得到什么样的回应

我曾尝试(未成功)使用下划线.js的memoize函数来执行此操作,但它没有按我预期的方式工作。但是,这个概念看起来是这样的:

   jquerySelect = function () {
                var elements = _.memoize(function (selection) {
                    return $(selection);
                });
                return elements;
            };
var jquerySelect = _.memoize(function (selection) {
                       return $(selection);
                   });
这里的想法是“return$(selection)”的实际结果工作执行一次,然后缓存并返回结果

我希望能够通过以下方式使用它:

utils.jquerySelect(".highlighted").find("span")
在这个简单的示例中,缓存的键是“.highlighted”,实用程序函数知道如何访问结果,从而避免再次遍历DOM。我的实现目前无法工作,因为每次都会命中“return”语句


我不确定这种方法是否有缺陷,但我感觉可能有缺陷。但是,如果您看到了实现此功能的方法,或者看到了更好的方法,请告诉我。

我可以具体谈谈memoize,但我可以说,您维护缓存jQuery集合的关联数组的策略是一个好主意。话虽如此,您需要考虑以下几点:

  • 缓存一个只在前端使用0或1次的选择器可能并不总是值得的
  • 如果试图计算元素集合的动态值(例如长度),则需要在获取值之前重新选择/缓存元素。例如:

    var$div=$(“div”)

    $div.length//说是1

    //…一些向页面添加一些div的代码

    $div.length//还是1

  • 我会考虑及时做你的缓存。换句话说,只缓存第一次需要的项


    这不是一个坏主意,事实上,你已经可以找到几十个类似的JQuery备忘录插件了。这种方法的主要挑战是知道何时可以使用已记忆的结果,以及何时由于DOM中的更改而无效。由于JQuery代码在DOM中添加、删除和更改节点的可能性与从DOM中选择节点的可能性相同,因此知道何时必须从记忆缓存中使选择器无效是一个非常重要的问题

    memoize插件解决这一问题的方法通常是提供一些替代语法,例如为您想要被记忆的选择器和/或您想要从中检索记忆结果的选择器提供
    $\(
    )。无论如何,这会向选择器添加额外的字符串/哈希查找。那么,最终,与本地缓存相比,这种缓存的真正优势是什么

    一般来说,最好进一步了解JQuery如何本质上是一个DSL,为DOM提供一元转换(也称为链接)

    例如,问题中的代码可以编写为:

    $("#myItem").doSomething().doSomethingElse();
    
    您甚至可以使用弹出选择器堆栈,因为在链中,结果已经在内部进行了记忆:

    $("#myItem").doSomething().find('a').hide().end().doSomethingElse();
    // a in #myItem are hidden, but doSomething() and doSomethingElse() happen to #myItem
    
    此外,大多数JQuery选择的成本可能被高估。ID选择(以
    #
    开头的选择器)被传递给快速DOM方法,如
    document.getElementById
    ,而不是Sizzle引擎。重复调用解析为单个DOM元素的选择器,例如
    $(this)
    ,对速度没有特别的影响


    如果在代码中的一个紧密循环中,速度确实是一个问题,那么几乎可以肯定,完全不用JQuery选择引擎来重构该部分是值得的。在我的测试中,您可以从本地选择器缓存中获得10-50%的性能提升,这取决于选择器的复杂性,从本地DOM选择器中获得的性能提升比从JQuery选择器中获得的性能提升高1000%。

    总体思路是一个好主意。不过,正如其他人所说,您需要小心,不要缓存特别需要重新查询的内容

    尝试失败的原因是您不正确地使用了
    。.memoize
    。它看起来是这样的:

       jquerySelect = function () {
                    var elements = _.memoize(function (selection) {
                        return $(selection);
                    });
                    return elements;
                };
    
    var jquerySelect = _.memoize(function (selection) {
                           return $(selection);
                       });
    
    memoize
    返回一个函数,然后调用该函数。它本质上是在处理缓存的函数周围创建一个包装器。

    这样做更有意义:

    var result = $("#myItem");
    result.doSomething();
    result.doSomethingElse();
    
    var myapp={};
    myapp.$body=$(document.body);
    myapp.$result = myapp.$body.find("#myItem").doSomething().doSomethingElse();
    myapp.$result.find("> .whatever")
    

    关于存储大型对象,如果你想在整个会话中重复使用,我一直在研究它&发现本地存储只允许普通静态对象,因此不接受myapp。例如$result,然后我放弃了这个想法。

    缓存是jquery中遵循的最佳实践

    我将缓存分为两类

    1。本地计算机:其范围仅在某些功能内

    例:

    使用时要记住的要点:

    一,。缓存由很少的函数访问的元素,或者说仅由该函数访问的元素

    二,。当动态添加元素时,每次都需要重新初始化元素,以便 本地缓存更好

    iii.将所有var声明和用于缓存的变量放在顶部

    iv.缓存一次,然后使用
    .filter('selector')
    .filter(函数)
    例如,
    elm.filter(':checked').dosomething()

    2。全局缓存