2010-10-03 72 views
0

我一直在写一个JS算法。它的快速铬和狗慢慢FF。在铬探查器中,我在一个方法中花费了10%,在FF中同样的方法是执行时间的30%。是否有JavaScript结构可以避免,因为它们在一个或另一个浏览器中真的很慢?JavaScript的构造,以避免?

我注意到的一件事情是,如果你做得够多,像简单变量声明这样的东西可能会很昂贵。我加快了我的算法noticable通过不做事喜欢

var x = y.x; 
dosomthing(x); 

,只是做

dosomething(y.x) 

例如。

+0

变量很便宜。赋值也很便宜,因为它只复制原始值或对象的引用。我不认为这可能是性能瓶颈。 – galambalazs 2010-10-03 16:57:15

+0

@galambalazs做了几十万次的事情时,我想每个任务都很重要? – hvgotcodes 2010-10-03 21:33:07

+0

绝对看看这[提案](http://area51.stackexchange.com/proposals/11464/code-review?referrer=aWNm_PdciyFqjFW8CUacGw2“代码审查”)。它几乎就在那里,只需要一点点支持:) – greatwolf 2011-01-17 22:08:20

回答

5

正如您发现的,不同的事情是不同的实现中的问题。根据我的经验,除非做出非常愚蠢的事情,否则没有太多的担心,在您的目标浏览器上进行测试之前,如果您遇到特定的性能问题,请优化JavaScript代码以使其速度更快。像通常的“倒计数到零”优化(for (i = length - 1; i >= 0; --i)而不是for (i = 0; i < length; ++i))这样的简单事情在跨实现方面甚至不可靠。所以我倾向于坚持编写相当清晰的代码(因为我希望能够维护它的人,这经常是我),然后担心如果和何时进行优化。

这就是说,通过the Google article看看tszming链接到his/her answer提醒我有一些性能的东西,我最初编写代码时要记住。下面列出了(有的从这篇文章中,有些没有):

  1. 当你建立一个长串出大量碎片的,令人惊讶的你通常如果你建立了片段的阵列获得更好的性能然后使用Array#join方法创建最终的字符串。如果我正在构建一个将添加到页面的大型HTML代码段,我会做很多工作。

  2. Crockford private instance variable pattern虽然很酷,功能强大,但价格昂贵。我倾向于避免它。

  3. with昂贵且容易被误解。躲开它。

  4. 内存泄漏最终当然是昂贵的。在与DOM元素进行交互时,在浏览器上创建它们相当容易。请参阅文章以获得更多详细信息,但基本上,使用jQuery,Prototype,Closure等良好的库来挂接事件处理程序(因为这是一个特别容易出现的区域,并且库有帮助),并避免将DOM元素引用存储在其他DOM上元素(直接或间接)通过expando属性。

  5. 如果你建立在浏览器中的内容的显著动态显示,innerHTML在大多数情况下快了很多比使用DOM方法(createElementappendChild)。这是因为高效地将HTML解析为其内部结构的是什么浏览器可以做,而且它们的速度非常快,使用优化的编译代码直接写入其内部数据结构。相反,如果使用DOM方法构建重要的树,则使用解释(通常)语言与抽象进行对话,浏览器必须进行翻译才能匹配其内部结构。我早些时候做了a few experiments,差别大概在一个数量级(赞成innerHTML)。当然,如果您正在建立一个大字符串以分配给innerHTML,请参阅上面的提示  —最好在阵列中构建碎片,然后使用join

  6. 缓存已知缓慢操作的结果,但不要过分,只要你需要它们就可以保留它。请记住保留参考的成本与再次查看的成本。

  7. 我一再听到有人说从一个包含范围访问变量(全局变量当然是最终的例子,但是你可以在其他变量中使用闭包变量)比访问本地变量要慢,当然由于范围链的定义方式,这在纯粹解释的非优化实现中是有意义的。但我从来没有看到它在练习被证明是一个显着的差异。 (Link to simple quick-and-dirty test)实际全局变量是特殊的,因为它们是window对象的属性,它是一个宿主对象,因此与用于其他作用域级别的匿名对象有所不同。但我希望你已经避免了全局变量。

下面是#6的一个例子。

for (i = 0; i < $$('.foo').length; ++i) { 
    if ($$('.foo')[i].hasClass("bar")) { // I forget what this actually was 
     $$('.foo')[i].setStyle({/* ... */}); 
    } 
} 

在原型,$$不昂贵的事情:我实际上是在以原型在几个星期前相关问题看到了这一点,搜索整个DOM树寻找匹配的元素(在这种情况下,与类元素“富”)。上面的代码搜索DOM 三次每个循环:首先检查索引是否在界限内,然后检查元素是否具有类“bar”,然后是何时设置样式。

这太疯狂了,无论浏览器上运行什么浏览器,它都会很疯狂。很显然你想简单地缓存这些查找:

list = $$('.foo'); 
for (i = 0; i < list.length; ++i) { 
    if (list[i].hasClass("bar")) { // I forget what this actually was 
     list[i].setStyle({/* ... */}); 
    } 
} 

...但进一步考虑它(如逆向工程到零)是没有意义的,它可以在一个浏览器和更慢的速度在另一个上。

+1

与'count down to 0'相关的是,我最近看到了另一个变体,我认为它很聪明(如果有点令人困惑):for(var i = arr.length ; i--;)' – 2010-10-03 15:21:36

+0

@Ryan::-)是的,我已经看到了一个(和它的堂兄,var i = arr.length; while(i - )...')。 – 2010-10-03 15:36:23

1

我不认为这是一个真正的性能的东西,但东西,以避免肯定,除非你真的知道发生了什么是:

var a = something.getArrayOfWhatever(); 
for (var element in a) { 
    // aaaa! no!! please don't do this!!! 
} 

换句话说,应该避免在数组上使用for ... in构造。即使在遍历对象属性时也很棘手。

另外,我最喜欢避免的是避免在声明局部变量时忽略var

+0

......或者确实是全局变量! – bobince 2010-10-03 14:56:44