如果已经在某个地方回答了这个问题,请原谅我。我搜索过,似乎这是一个相当具体的案例。
以下是JSON的示例(注意:这是非常剥离 - 这是动态加载的,目前有126条记录):
var layout = {
"2":[{"id":"40","attribute_id":"2","option_id":null,"design_attribute_id":"4","design_option_id":"131","width":"10","height":"10",
"repeat":"0","top":"0","left":"0","bottom":"0","right":"0","use_right":"0","use_bottom":"0","apply_to_options":"0"},
{"id":"41","attribute_id":"2","option_id":"115","design_attribute_id":"4","design_option_id":"131","width":"2","height":"1",
"repeat":"0","top":"0","left":"0","bottom":"4","right":"2","use_right":"0","use_bottom":"0","apply_to_options":"0"},
{"id":"44","attribute_id":"2","option_id":"118","design_attribute_id":"4","design_option_id":"131","width":"10","height":"10",
"repeat":"0","top":"0","left":"0","bottom":"0","right":"0","use_right":"0","use_bottom":"0","apply_to_options":"0"}],
"5":[{"id":"326","attribute_id":"5","option_id":null,"design_attribute_id":"4","design_option_id":"154","width":"5","height":"5",
"repeat":"0","top":"0","left":"0","bottom":"0","right":"0","use_right":"0","use_bottom":"0","apply_to_options":"0"}]
};
我需要匹配正确的值组合。这是我目前使用的功能:
function drawOption(attid, optid) {
var attlayout = layout[attid];
$.each(attlayout, function(k, v) {
// d_opt_id and d_opt_id are global scoped variable set elsewhere
if (v.design_attribute_id == d_att_id
&& v.design_option_id == d_opt_id
&& v.attribute_id == attid
&& ((v.apply_to_options == 1 || (v.option_id === optid)))) {
// Do stuff here
}
});
}
问题是我可能会迭代10-15个布局(独特的attid),任何给定的布局(attid)可能有多达50种可能性,这意味着这个循环正在运行很多。
考虑到必须匹配的多个标准,AJAX调用会更好吗? (这个JSON是通过PHP动态创建的,所以我可以创建一个可以更有效地执行此操作的PHP函数), 或者我完全错过了有关如何在JSON对象中查找项目的内容?
与往常一样,欢迎任何改进代码的建议!
修改
我为没有说清楚而道歉,但这个问题的目的是找到一种方法来改善性能。这个页面有很多javascript,这是我知道性能低于它的位置。
答案 0 :(得分:5)
首先,您应该衡量,并且只有在存在真正的性能问题时才会采取行动。您需要200毫秒的确切数字或80%的时间。 "它运行很多"什么都没有意义。浏览器可以非常快地循环。
您可以像其他人提到的那样改进常数因子,例如使用原生for循环而不是 jQuery.each 。在这种情况下,追逐全局变量对你的帮助太大了。
如果你真的想提高效率,你应该找到比O(n)更好的算法。假设您只使用此数据来查找符合特定条件的元素,您可以使用JS对象作为哈希来实现O(1)性能。
仅举例说明具体案例:
var layout = {
"2": { "2,,4,131,10,0": ["40", "93"], "2,115,4,131,0": ["41"] },
"4": { ... },
...
};
在php中生成此输出相当容易,然后您只需使用查找来查找符合您特定条件的ID。
答案 1 :(得分:2)
我的第一个建议是停止使用$.each
,如果你想要尽可能地挤出一点性能。 jQuery.each比传统循环做得更多。在浏览器的调试器运行时查看this jsFiddle(即Safari / Chrome的Web开发人员工具)并逐步完成,直到执行从jQuery完全返回。
作为参考,小提琴的代码是:
var myArr = [{"foo":"bar"},{"answer":42}];
debugger;
$.each(myArr, function(k, v) {
console.log(k + ': ');
console.dir(v);
});
现在浏览the second version:
var myArr = [{"foo":"bar"},{"answer":42}],
i, j;
debugger;
for (i = 0, j = myArr.length; i < j; i += 1) {
console.log('myArr[' + i + ']: ');
console.dir(myArr[i]);
}
请注意,第二个版本中执行的操作要少得多。所以这是微小位的性能提升。
其次,尽可能多地消除本地范围之外的查找次数。即使你缓存了对全局变量的引用(boo!),你也可以save a lot of time,因为这个循环可能会被执行数百次。所以而不是:
function foo(a, b) {
if (a === globalA && b === globalB) {
// Do stuff
}
}
你会这样做:
function foo(a, b) {
var gA = globalA,
gB = globalB;
if (a === gA && b === gB) {
// Do stuff
}
}
至于根据对象成员配对条件,我没有看到其他可以改进的东西。您正在检查的对象属性是顶级的,您正在查看每个对象的本地实例(因此范围链查找很短)。
如果不了解这实际上应该如何运作,那么这些是我能提出的最佳建议。但是,我可以猜测,您从简单的JSON数据开始的想法将是一个很大的改进。如果您知道布局及其约束是什么,那么从服务器请求特定细节将意味着您不必检查这么多条件。您可以简单地向服务器询问您实际需要实现的细节并循环遍历(更新DOM或其他)。
答案 2 :(得分:2)
恕我直言,一个简单的hashmap索引可能效果最好。这确实需要您提前循环数据,但索引可以很容易地附加到和缓存。
生成索引后,对于查找应该是O(1),并且每个键将处理多个条目。
var layout = {
"2":[[...], ...],
"5":[[...], ...]
};
var index = {};
function makeKey(data) {
return data.join('_');
}
for(var l in layout) {
var cur = layout[l];
for(var i in cur) {
var item = cur[i];
var key = makeKey([item.p1, item.p2, ...]);
index[key] = index[key] || [];
index[key].push(item);
}
}
function find(attid, optid) {
var key = makeKey([attid, optid, 1, d_att_id, ...]);
return index[key]; //this is an array of results
}
答案 3 :(得分:1)
我看到你在搜索 5个字段:v.design_attribute_id,v.design_option_id,v.attribute_id,v.apply_to_options,v.option_id。
你可以做的是在名为“key”的对象中添加一个额外的字段,该字段是这些字段中值的组合。
这是一个例子
{
"key": "4_131_2_0_0" //i picked 0 to represent null, but you can pick any number
"id": "40",
"attribute_id": "2",
"option_id": null,
"design_attribute_id": "4",
"design_option_id": "131",
"width": "10",
"height": "10",
"repeat": "0",
"top": "0",
"left": "0",
"bottom": "0",
"right": "0",
"use_right": "0",
"use_bottom": "0",
"apply_to_options": "0"
}
请注意,您必须规范化每个值的长度。 这意味着如果一个对象optionId为1而另一个对象optionID为566则必须表示 密钥字符串中的第一个选项ID为001。
使用此字段,您可以在将数组返回到客户端之前对服务器端的数组进行排序。
然后,您可以使用二进制搜索在客户端上查找值。
使用此处的二进制搜索实现 http://www.nczonline.net/blog/2009/09/01/computer-science-in-javascript-binary-search/
您的搜索功能类似于
function drawOption(attid, optid) {
var attlayout = layout[attid];
var needle = d_att_id + "_" + d_opt_id + "_" + attid + "_" + optid; //remember to normalize length if you have to
var idx = binarySearch(attlayout,needle);
var item;
if(idx !== -1){
item = attlayout[idx];
//do something
}
}
您可以尝试使用此复合键构思的另一种方法是让服务器返回 映射的一个大对象中的布局对象 attid,v.design_attribute_id,v.design_option_id,v.attribute_id,v.apply_to_options,v.option_id
然后你可以在O(1)时间内查找。 它看起来像
function drawOption(attid, optid) {
var needle = attid + "_" + d_att_id + "_" + d_opt_id + "_" + attid + "_" + optid; //remember to normalize length if you have to
var item = layout[needle];
if(typeof item !== "undefined"){
//do something
}
}
答案 4 :(得分:0)
在尝试改进代码时,最好使用firebug分析来检查哪些函数需要时间。您可以通过单击firebug控制台面板中的配置文件按钮进行配置,然后运行代码或使用代码中的firebug's profiling commands
根据您提供的代码,只能给出一些改进点。
答案 5 :(得分:0)
我之前遇到过这样的问题,我的js对象数组包含8千条记录以及更多。 我的经验不是关于性能,而是关于代码的可读性,可维护性和可扩展性。
因此我在2年前开发了一个JS对象查询库:JSOQL http://code.google.com/p/jsoql/
它像SQL一样,允许您使用类似于SQL的语法查询对象的js数组。
示例用法是这样的,我真的不记得了,但您可以在下载选项卡中下载示例用法。
new JSQOL().Select([field1, field2, field3 ...]).From({ ... }) .Where(fn) .Offset(int) .Limit(int) .Get();
注意: {...}是你的对象数组,或者是它自己的对象。
希望有所帮助,如果您需要更多信息,可以给我发消息。
答案 6 :(得分:0)
它无处不在,但你的问题听起来好像可以用webworkers来完成
如果你没有网络工作者,我会看到的另一件事是试图不阻止ui长。如果您可以将其分成大约40ms的位,然后在几毫秒之后设置下一个chunck,那么用户将获得更愉快的体验。这需要一点点摆弄,但是当事情需要超过50到100毫秒之间时,用户会开始注意到东西
答案 7 :(得分:-1)
答案 8 :(得分:-1)
这种技术可能会以更多的内存为代价,从而产生更好的性能。
我只是为了说明这个概念,我的代码示例很简单。
首先,您希望将JSON数据预处理到一些充当索引的其他数组中。以下是预处理后最终数组的外观示例:
var layouts_by_attribute = {
// attribute_id => array(layouts)
2: [40, 41, 44],
5: [326]
};
var layouts_by_design_attribute_id = {
// design_attribute_id => array(layouts)
4: [40, 41, 44, 326]
};
现在可以非常快速地按属性查找布局:
function findByAttribute(attribute_id) {
return layouts = layouts_by_attribute[attribute_id];
}
function findByDesignAttribute(design_attribute_id) {
return layouts = layouts_by_design_attribute[design_attribute_id];
}