【问题标题】:Is JavaScript function call faster through prototype or direct reference?JavaScript 函数调用是通过原型还是直接引用更快?
【发布时间】:2011-04-05 00:13:25
【问题描述】:

在 JavaScript 中,假设我想从 bObj 内部调用 aObj.myMethod()。在我的应用程序中,从设计的角度来看,aObj 是 bObj 的基类。 JavaScript 是一种后期绑定语言,这意味着 myMethod 应该在运行时解析。函数解析是否更快

//////////如果

1-我很自然地使用我的设计并说 bObj.prototype=aObj 然后在运行时我调用 bObj.myMethod:

function bObj(){...};

bObj.prototype=aObj;


//later
var myBObj=new bObj();
myBObj.myMethod();

/////////////////////或

2- 原型中的函数解析可能很慢,所以我将 aObj 作为属性保留在 bObj 中,并从 bObj 内部调用 aObj.myMethod()

function bObj()
{
  this.myAObj=new aObj();
  ...
}     

//later:
var myBObj=new bObj();
myBObj.myAObj.myMethod();

我主要关心的是执行速度。在我的应用程序中,myMethod 每秒被调用数百万次。我知道大多数浏览器都会缓存指向最近调用的函数的指针,因此在这两种情况下,函数解析过程都会加快速度。然而,任何人都可以提供有关这两种情况下函数解析机制的更多细节,并提供一些见解,即哪种方法可能更快?解析机制在所有浏览器中都相同还是完全依赖于浏览器?

【问题讨论】:

  • 百万次/?哇,这么多!
  • 您是否尝试过在不同的浏览器中同时分析两种方式?
  • 你可以在jsperf.com设置你的两个场景并自己测试一下
  • 从逻辑上讲,属性解析链越短访问速度越快,但现实中不一定如此。在您发布的代码中,在这两种情况下都有两个查找 myMethod() ,因此您没有获得任何东西。此外,调用 myMethod 的方式会影响其 this 关键字的值,在第一种情况下它将是 myBObj,在第二种情况下是 myAObj。因此,请彻底考虑您的设计 - 有效的代码比(略微)更快的错误代码更好。
  • @user680999:我的 cmets 关于性能的。这是一个测试用例来证明我的观点:jsperf.com/lookupperf。短链在所有浏览器(包括 iOS 上的 Safari)中较慢,但 IE 6 除外,IE 6 的短链要快 3 倍 - 但较新版本的 IE 可能会改变这一点。鉴于与短链的 1 相比,长链是 7 次查找,我认为这已经足够证明了。你的继承链长于 7 吗?底线是,不要仅仅为了性能而优化查找链。

标签: javascript performance late-binding prototypal-inheritance function-call


【解决方案1】:

就您引用的方式而言,您是对的,“函数解析可能很慢”。 那么让我们来看看..

在原型链查找之后,如果您将 myMethod 设为原型方法,例如:aObj.prototype.myMethod=somemethod,那么第一种方法 myBObj.myMethod() 将在第二次尝试时获得“分辨率命中”由于未设置 myBObj 实例 myMethod,因此它命中了继承的原型方法。

第二种方法,myBObj.myAObj.myMethod(),在第二次尝试时会在遇到原型方法时获得“分辨率命中”,因为实例方法未设置(myAObj=new aObj() 确实如此)尚未设置 myAObj.myMethod 将设置 myAObj.prototype.myMethod, 所以你这样做的方式没有区别。

从您执行此操作的任何一种方式中获得性能提升 要么确保您要调用的实例方法已设置,然后引用它:

bObj.myMethod=bObj.prototype.myMethod;
bObj.myMethod();

myAObj.myMethod=myAObj.prototype.myMethod;
bObj.myMethod();

在这两种情况下,第一次查找都会获取实例方法,然后使用哪个更好。

要获得最佳性能增益,请完全消除查找 并引用原型方法:

myBobj.prototype.myMethod();

myBObj.myAObj.prototype.myMethod();

在最后两种情况下,不需要“函数解析”。

虽然我们都知道 Function 函数在每次使用时都会被解释 并且声明的函数被编译(解释)一次,因此速度更快,如果将声明的函数设置为对象的原型实际上使其执行速度更快,这仍然是一个谜。

如果你能找到这个,那么你就会确切地知道如何获得一个函数,任何函数, 以最快的速度执行:声明它或将其设置为原型函数,以最好的为准,如果原型方法更快,则通过直接引用原型方法来避免任何原型链查找。

【讨论】:

    【解决方案2】:

    我刚刚针对这个特定案例完成了几项性能测试。它使用 Mozilla Rhino 1.7R3 以优化模式运行。

    您的问题实际上是关于属性查找的。一旦在可用范围链中找到属性(在您的情况下,具有函数值),进一步的操作在两种情况下执行相同。

    显而易见的结果是查找原型上定义的函数的速度较慢。平均而言,调用原型函数需要多花 35% 的时间。直接调用本地函数与直接调用全局范围内的函数得到了相同的结果。

    自己的属性解析速度更快,因为它们的范围在原型之前。

    做出你的决定。请记住,原型非常适合代码维护和对象重用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-24
      • 2017-11-06
      • 2011-09-17
      • 2011-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多