跳出嵌套循环:使用return还是label/break?

5
我正在使用一个JavaScript函数来设置全局变量。下面有两个非常愚蠢的示例函数,一个使用标签来跳出嵌套循环,另一个使用空返回值。
我的问题是:在性能问题上,哪个更好?(为了争辩的缘故,假设这样做了几百万次。) 使用空返回值
function foo() {
    for(var i = 0; i < 100; ++i) {
        for(var j = 0; j < 100; ++j) {
            if(i * j == 50) {
                myGlobal = j;
                return;
            }
        }
    }
}

Using label and break

function foo() {
    dance:
    for(var i = 0; i < 100; ++i) {
        for(var j = 0; j < 100; ++j) {
            if(i * j == 50) {
                myGlobal = j;
                break dance;
            }
        }
    }
}

我知道只有当我的内部条件被满足/我完成我的任务之后,我才会做任何事情。

谢谢!


2
你尝试过进行性能分析吗?你已经完成了所需工作的三分之二,为什么不进行性能分析并查看结果呢? - George Stocker
@GeorgeStocker *脸掌。不确定为什么我没有走那最后一步。请查看我下面发布的答案-并告诉我您是否认为测试用例是正确的。谢谢! - Matthew Herbst
4个回答

6

经过一些测试(通过Chrome控制台,MBP 2013,OSX 10.9,Intel i7 @ 2.8GHz,16GB DDR3),结果非常有趣。我进行了两种类型的测试。第一个测试使用return和label/break来跳出嵌套循环。第二个测试使用直接的return和label/break,函数中没有其他内容。测试代码如下:

function r() {
    for(var i = 0; i < 10; ++i) {
        for(var j = 0; j < 10; ++j) {
            if(i*j == 50) {
                return;
            }
        }
    }
}

function b() {
    dance:
    for(var i = 0; i < 10; ++i) {
        for(var j = 0; j < 10; ++j) {
            if(i*j == 50) {
                break dance;
            }
        }
    }
}

function r2() {
    return;
}

function b2() {
    dance:
    break dance;
}

var startTime;
var endTime;

console.log("Return test");
startTime = Date.now();
for(var i = 0; i < 1000000000; ++i) {
    r2();
}
endTime = Date.now();
console.log(endTime - startTime);

console.log("Break test");
startTime = Date.now();
for(var i = 0; i < 1000000000; ++i) {
    b2();
}
endTime = Date.now();
console.log(endTime - startTime);

当比较跳出嵌套循环(函数 r() 和 b())时,使用 return 的表现始终更好。但是,在函数中只使用 return 或 label/break(函数 r2() 和 b2())时,label/break 的表现更快。测试结果如下:

测试 1,使用 10000000 次迭代

使用 return 跳出嵌套循环的 3 次运行后的平均运行时间(毫秒):1215ms

使用 label/break 跳出嵌套循环的 3 次运行后的平均运行时间(毫秒):1522ms

测试 2,使用 1000000000 次迭代 // 迭代次数增加了两个数量级

使用 return 的 3 次运行后的平均运行时间(毫秒):1879ms

使用 label/break 的 3 次运行后的平均运行时间(毫秒):1862ms

因此:

对于跳出嵌套循环,使用 return 约快 25%

对于科学计算/HPC,使用 label/break 约快 1%


0

我个人认为,在函数不返回任何东西的情况下,使用空的return语句来提前终止执行是没有问题的。这比使用标签更加简洁,而且也更加与语言无关。许多编程语言都不支持像你示例中所用的带标签的for循环,因此对于那些来自其他缺少该特性的语言的人来说,空的return语句会更容易理解。


0

更新:

这里有好的信息:为什么JavaScript函数总是返回一个值?,第一个答案说:“因此,return和函数执行到结束的语义相匹配。”所以即使你使用break,在执行结束时它将返回与使用return相同的结果


1
我注意到的一件事情是,所有缺少返回语句的 JavaScript 函数似乎都会返回“undefined”。这只是 Chrome 控制台在跟我开玩笑吗,还是确实是语言规范? - Matthew Herbst
1
啊,好观察力,我在这里找到了一些信息:https://dev59.com/xWEi5IYBdhLWcg3w0fFR,第一个答案说:“因此,返回和函数执行到其结束的语义匹配。”所以我想这真的没关系。 - matthijs

0
两者性能相同;前者更易读,但后者使得在循环之后需要添加更多指令时更容易修改该函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接