我正在研究优化单页应用程序的方法,目前我正专注于jQuery选择器。
我不是javascript专家,但我的理解是将jquery选择器的结果存储在变量中以便重用,而不是重新查询dom,这样做的效率要高得多。
因此,例如,而不是:
$("#myItem").doSomething();
$("#myItem").doSomethingElse();
这样做更有意义:
var result = $("#myItem");
result.doSomething();
result.doSomethingElse();
另外,我的理解是,使用附加到现有jQuery对象的find()选择器可以获得很大的性能优势,以减少必要的查询量:
$("#myItem").find(".highlighted");
我有兴趣探索存储许多选择器的可能性,这些选择器在我们的应用程序中不仅在局部变量中重复使用,而且可能在某个地方使用散列或外部函数。我不知道这是否最佳,但我很好奇收到的回复。
我尝试(不成功)使用Underscore.js的memoize函数来执行此操作,但它没有按照我预期的方式工作。但是,这个概念看起来像这样:
jquerySelect = function () {
var elements = _.memoize(function (selection) {
return $(selection);
});
return elements;
};
这里的想法是“返回$(选择)”的实际结果工作执行一次,之后结果被缓存并返回。
我希望能够以下列方式使用它:
utils.jquerySelect(".highlighted").find("span")
在这个简单的例子中,缓存的关键是“.highlighted”,实用程序函数知道如何访问结果,从而节省了遍历DOM的工作。我的实现目前不起作用,因为每次都会发出“return”语句。
我不确定这种方法是否存在缺陷,但我感觉可能存在缺陷。但是,如果您看到一种方法可以使用,或者您看到更好的方法,请告诉我。
答案 0 :(得分:3)
这不是一个坏主意,事实上你已经可以在那里找到几十个类似的JQuery memoization插件。您的方法面临的主要挑战是知道何时可以使用已记忆的结果,以及何时由于DOM的更改而使其无效。由于JQuery代码可以添加,删除和更改DOM中的节点,因为它们可以从中进行选择,因为知道何时必须从memoized缓存中使选择器无效是一个非常重要的问题。
memoize插件解决这个问题的方法通常是提供一些替代语法,例如$_()
用于想要记忆的选择器和/或要从中检索记忆结果的选择器。但是,无论如何,这会为选择器添加额外的字符串/哈希查找。那么,最终,本地缓存的真正优势是什么呢?
一般来说,最好更多地了解JQuery本质上是如何为DOM提供monadic转换(也称为链接)。
例如,您可以编写问题中的代码:
$("#myItem").doSomething().doSomethingElse();
您甚至可以使用.end()
来弹出选择器堆栈,因为在链中结果已经在内部进行了记忆:
$("#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%的性能提升,具体取决于选择器的复杂性,以及通过JQuery选择器从本机DOM选择器获得1000%的性能提升。
答案 1 :(得分:0)
我可以专门讲述memoize,但我可以说你维护缓存jQuery集合的关联数组的策略是个好主意。话虽如此,你需要考虑一些事项:
如果您正在尝试计算关于元素集合的动态(例如长度),则需要在获取值之前重新选择/重新缓存元素。例如:
var $ div = $(“div”);
$ div.length; //说它是1
// ...为页面添加一些div的一些代码
$ div.length; //还是1!
我会考虑“及时”进行缓存。换句话说,只在第一次需要时缓存项目。
答案 2 :(得分:0)
总体思路是好的。正如其他人已经说过的那样,您需要注意不要缓存特别需要重新查询的内容。
您尝试失败的原因是您错误地使用了_.memoize
。它看起来像这样:
var jquerySelect = _.memoize(function (selection) {
return $(selection);
});
memoize
返回一个您随后会调用的函数。它实际上是在你的函数周围创建一个处理缓存的包装器。
答案 3 :(得分:0)
var myapp={};
myapp.$body=$(document.body);
myapp.$result = myapp.$body.find("#myItem").doSomething().doSomethingElse();
myapp.$result.find("> .whatever")
关于存储大型对象,如果你想在整个会话中重复使用,我一直在研究它和它。发现本地存储仅允许普通静态对象,所以不接受myapp。例如$ result,然后我放弃了这个想法。
答案 4 :(得分:-1)
缓存是jquery中遵循的最佳实践。
我将缓存分为两类。
<强> 1。本地cahching :其范围仅在某个函数内。
前:
function doSome(){
var elm=$('selector');
elm.something1().something2() .... chain it on one
}
使用时要注意的要点:
我。缓存由极少数函数访问的元素,或仅由该函数说明。
II。当动态添加元素时,每次都需要重新初始化它 本地缓存更好。
III。将所有var声明保留在顶部以及用于缓存的变量。
IV。缓存一次,稍后使用.filter('selector')
或.filter(function)
进行过滤
恩。 elm.filter(':checked').dosomething();
<强> 2。全局缓存所有功能的范围
用于全局缓存,声明一个对象,并将所有缓存作为该变量中的键值对。
例如:
var global={};
$(document).ready(function(){
global.sel1=$('selector1');
global.sel2=$('selector2');
});
//如果要在页面顶部声明全局变量,则remeber始终在文档就绪函数中添加cahing变量。由于元素不会出现在dom中,因此选择器将返回undefined。
如果您将所有脚本放在我喜欢的页面上而不是您可以使用
var global={
sel1:$('selector1'),
sel2:$('selector2')
} ;
指出要记住
全局追逐的setter和getter函数
function getGlobal(selector){
//if not present create it .
if(!global[selector]){
global[selector]=$(selector);
}
return global[selector];
}
//to use it
var elm=getGlobal('selector');