Javascript JS:调用一个函数需要多长时间?

Javascript JS:调用一个函数需要多长时间?,javascript,performance,function,math,callstack,Javascript,Performance,Function,Math,Callstack,所以,我正在编写一个2d Javascript物理模拟程序。性能很好,但我正在进行优化以使其更好。所以,因为这个程序使用了很多物理几何,我在程序中做了几个毕达哥拉斯定理的计算。总共大约有五次计算;它们合起来每秒运行大约一百万次。所以,我想如果我把简单的毕达哥拉斯定理代码放到一个新函数中并调用它,它会提高性能;毕竟,通过这种方式,浏览器可以减少编译工作量。所以,我在Firefox中运行了代码,得到了。。。。该计算的执行时间增加了4000000% 怎么做?这是相同的代码:Math.sqrt(x*x+

所以,我正在编写一个2d Javascript物理模拟程序。性能很好,但我正在进行优化以使其更好。所以,因为这个程序使用了很多物理几何,我在程序中做了几个毕达哥拉斯定理的计算。总共大约有五次计算;它们合起来每秒运行大约一百万次。所以,我想如果我把简单的毕达哥拉斯定理代码放到一个新函数中并调用它,它会提高性能;毕竟,通过这种方式,浏览器可以减少编译工作量。所以,我在Firefox中运行了代码,得到了。。。。该计算的执行时间增加了4000000%

怎么做?这是相同的代码:Math.sqrt(x*x+y*y),那么将其作为函数添加会如何降低速度呢?我假设原因是函数调用需要时间,而不执行代码,加上每秒一百万次的延迟会使它变慢吗

这对我来说似乎相当令人担忧。这是否也适用于预定义的js函数?这似乎不太可能,如果是这样,他们如何避免呢

过去的代码是这样的:

function x()
{
    dx=nx-mx;
    dy=ny-my;
    d=Math.sqrt(dx*dx+dy*dy);
    doStuff(...
}
我尝试的是:

function x()
{
    dx=nx-mx;
    dy=ny-my;
    d=hypo(dx,dy);
    doStuff(...
}
function hypo(x,y)
{
    return Math.sqrt(x*x+y*y);
}

谢谢

函数调用在JS从未使用过的预编译语言中可以忽略甚至优化。除此之外,很大程度上取决于浏览器

它们是解释语言中所有性能的死亡,直到最近,JS才开始使用解释语言。大多数现代浏览器都有JIT(即时)编译器,这是对过去JS解释器的巨大升级,但我相信对另一个作用域的函数调用仍然会花费一些开销,因为JS的调用对象必须确定实际调用的是什么,这意味着在各个作用域链上下移动

因此,作为一条一般规则:如果你关心IE8和更低版本的Chrome和Firefox,请避免函数调用。尤其是内部循环。对于JIT浏览器,我希望在另一个函数中定义一个函数通常是有益的(但我仍然会进行测试,因为这是IE9的全新技术,对其他所有人来说都相对较新)

还有一件事需要警惕。如果一个函数特别复杂,JIT可能不会对其进行任何优化

但需要理解的重要一点是,当某个东西被锁定并且只在上下文中调用时,比如函数中的函数,JIT应该很容易进行优化。在函数外部定义时,它必须确定要准确调用该函数的哪个定义。它可能在一个外部函数中。它可能是全球性的。它可能是窗口对象的构造函数原型的属性,等等。。。在一种函数是第一类的语言中,这意味着它们的引用可以像传递数据一样作为参数传递,在当前上下文之外,您无法真正避免这一步

所以试着在X中定义hypo,看看会发生什么

解释时代的另外两个一般提示在JIT中可能仍然很有价值:

  • someObject.property
    中的“.”运算符是一个值得缓存的进程。它会增加开销,因为每次使用它时都有一个关联的调用对象查找过程。我想Chrome不会保留这个过程的结果,因为对父对象或原型的更改可能会改变它在给定上下文之外实际引用的内容。在您的示例中,如果循环正在使用x(如果x与JITs中的循环定义在同一个函数中,则可能是正确的,甚至是有用的-在解释器中是谋杀),我将尝试在hypo中使用它之前将Math.sqrt分配给var。在当前函数的上下文之外有太多的引用可能会导致一些JIT决定不值得费心优化,但这纯粹是我的猜测

  • 以下可能是循环阵列的最快方法:

注意:由于某些原因,代码块在这里不起作用


这样做会很有帮助,因为它基本上将inc/递减步骤和逻辑比较变形为递减,完全不需要左/右比较运算符。请注意,在JS中,右边的减量运算符意味着我将被传递以进行求值,然后在块内使用之前减量
while(0)
的计算结果为false。

令我惊讶的是,按照Erik的建议缓存查找对提高我的浏览器(Chromium,Linux)的性能没有多大作用,反而会影响性能:

慢于

甚至调用别名也会比较慢

var _sqrt = Math.sqrt; // _sqrt is slower than Math.sqrt!
但话说回来,这并不是一门精确的科学,现实生活中的测量方法仍然可能有所不同


尽管如此,我还是要使用
Math.sqrt

函数是否定义在每秒运行一百万次的范围之外?而且,浏览器“要做的编译更少”并不是真的,因为您将它放在函数中。。。事实上,应该是差不多的,特别是因为编译是一项启动工作。但是@alex可能知道了你400%减速的原因:)掌握你所说的确切代码是很重要的。尝试使用注意:当您调用函数时,浏览器必须为新变量分配内存,并将值复制到其中(即函数的参数)。这无疑会增加额外的开销+1,因为没有将代码放在JSFIDLE上,而是将其发布在这里,这是在这里提问的正确方式,对于一个问得很好的问题(在编辑添加代码之后)。一个JSFIDLE链接作为对您文章的额外引用本来可以,但是在这里有实际的代码,以便将来遇到它或搜索它的用户可以使用它是正确的方法。:)谢谢一个很好的解释!在较大的函数中定义hypo函数需要花费太多的时间,我需要在其他函数中使用它,因此对我来说不值得。不过出于好奇,我确实试过了
var optimizedDistance = (function () { 
    var sqrt = Math.sqrt;
    return function (x, y) { return sqrt(x * x + y * y); }
})();
var unoptimizedDistance = function(x, y) {
    return Math.sqrt(x * x + y * y);
}
var _sqrt = Math.sqrt; // _sqrt is slower than Math.sqrt!