jsc.tools.road.correctType = function() {
for(row = jsc.data.selection.startX - 1; row <= jsc.data.selection.endX + 1; row++) {
for(col = jsc.data.selection.startY - 1; col <= jsc.data.selection.endY + 1; col++) {
if(jsc.data.cells[row-1][col].type != "road" && jsc.data.cells[row+1][col].type != "road" && jsc.data.cells[row][col].type == "road") {
jsc.ui.addClassToCell("horz", row, col);
}
else {
jsc.ui.removeClassFromCell("horz", row, col);
}
if(jsc.data.cells[row][col-1].type != "road" && jsc.data.cells[row][col+1].type != "road" && jsc.data.cells[row][col].type == "road") {
jsc.ui.addClassToCell("vert", row, col);
}
else {
jsc.ui.removeClassFromCell("vert", row, col);
}
}
}
};
// Elsewhere
jsc.ui.addClassToCell = function(class, x, y) {
$("#" + x + "-" + y).addClass(class);
};
jsc.ui.removeClassFromCell = function(class, x, y) {
$("#" + x + "-" + y).removeClass(class);
};
上面的代码运行得非常慢。我无法弄清楚为什么。它使用的是jQuery 1.3.2。有什么方法可以优化它吗?
编辑:代码是我作为个人项目制作的javascript游戏的一部分。它基本上是一个Simcity克隆。这段代码检查道路的每个部分的相邻单元,并将类(以及背景图像)改变为正确的单元以使道路图像正确排列,例如,水平,垂直和交叉(无类)道路图像。
编辑2:提供一些上下文的更多细节。
jsc.data.cells是一个200 x 200的数组。每个数组元素都是一个具有如此属性的对象(默认显示):{type:null,develop:false,powered:false,watered:false,hasTransport:false,wealth:0,quality:0}。
它的对手是在UI中,它基本上是一个巨大的表。 (再次200 x 200)。每个单元格在整个程序中都添加了许多CSS类,以更改背景图像(例如,将其更改为道路,.com.developed以使其成为开发的商业区域)。表格单元格的每个都具有#x-y形式的id,即jsc.ui.addClassToCell和jsc.ui.removeClassFromCell编辑。
编辑3:修正了以数字开头的ID。现在尝试一些优化。
答案 0 :(得分:4)
使用O()表示法的简短估计:
for(row) ... O(N)
for(col) ... O(N)
$().addClass/removeClass ... O(N^2)
$()甚至在嵌套for。
中被调用两次所以你最终得到O(N ^ 4)
您可以通过在jsc.data.cells [row] [col]的as属性中缓存计算出的类来优化它,例如
jsc.data.cells[row][col].horz = 1; // don't set class "horz" if not present
jsc.data.cells[row][col].vert = 1;
并在HTML表格中创建单元格时使用缓存数据,而不是为每个单元格调用$()。
答案 1 :(得分:2)
我只能提供一些提示,但不知道它们是否有用。无法测试您的代码。
1-st:在本地函数范围内声明变量。我的意思是行和col变量,你声明为全局变量(缺少var语句)。对全局变量的访问需要更长时间(AFAIK),而不是本地范围变量。
var row = jsc.data.selection.startX-1;
var col = jsc.data.selection.startY-1;
2-nd:缓存对公共对象的引用。在这里,您可以存储jsc.data和/或jsc.data.selection和jsc.data.cells的引用。 IIRC,对象属性的访问是线性的。
jsc.tools.road.correctType = function() {
var data = jsc.data, selection = data.selection, cells = jsc.data.cells, ui.jsc.ui;
for(var row = selection.startX - 1, endX = selection.endX + 1, endY = selection.endY + 1; row <= endX; ++row) {
for(var col = selection.startY - 1; col <= endY; ++col) {
if(cells[row-1][col].type != "road" && cells[row+1][col].type != "road" && cells[row][col].type == "road") {
ui.addClassToCell("horz", row, col);
} else {
ui.removeClassFromCell("horz", row, col);
}
if(cells[row][col-1].type != "road" && cells[row][col+1].type != "road" && cells[row][col].type == "road") {
ui.addClassToCell("vert", row, col);
} else {
ui.removeClassFromCell("vert", row, col);
}
}
}
};
我还将endY变量的声明移动到外部循环,因此不会在每次访问内部循环时计算它。
- 编辑
希望您知道,ID属性值cannot start with a number与您一样,例如。 #2-3
答案 2 :(得分:2)
根据您选择的大小,您可能会进行大量的条件检查和DOM编辑。
通过注释掉addClassToCell和removeClassFromCell的内容并比较运行时间,您可以了解条件检查或dom编辑是否花费最多时间,从而确定哪一个是优化的最佳候选者。
答案 3 :(得分:2)
通常你可以显着优化这些循环;
for( var x = 0; x < someMethod(); x++ ) {
//... do stuff
}
用这样的东西换掉它们
var x = someMethod();
while( x-- ) {
//...do stuff
}
虽然它在语义上略有不同,但只要你不依赖循环中的顺序(顺序相反),它通常会很好地运作
即使你不能改变顺序,你也可以通过移动实际循环的someMethod调用OUT来显着改进代码,因为在许多JS实现中,每次迭代都会调用一次...
答案 4 :(得分:1)
使用memoizer或本地缓存来存储您已创建的jQuery对象。这将减少$
函数调用的数量。
var cache = {}, selector;
for (/* … */) {
selector = "#" + x + "-" + y;
if (!cache[selector]) {
cache[selector] = $(selector);
}
// cache[selector] refers to the same object as $("#" + x + "-" + y)
}