javascript构造避免?

时间:2010-10-03 14:00:48

标签: javascript algorithm optimization

我一直在编写JS算法。它在铬和狗的速度快,在FF慢。在chrome profiler中,我在方法中花费<10%,在FF中,相同的方法是执行时间的30%。是否有javascript结构要避免,因为它们在一个浏览器或其他浏览器中确实很慢?

我注意到的一件事是,如果你做得足够多,像简单的变量声明这样的东西可能会很昂贵。我通过不做像

这样的事情来加速我的算法
var x = y.x;
dosomthing(x);

并且正在做

dosomething(y.x)
例如,

3 个答案:

答案 0 :(得分:5)

正如您所发现的,不同的实现中存在不同的问题。根据我的经验,除非做出非常愚蠢的事情,否则在将目标浏览器进行测试时,除非遇到特定的性能问题,否则优化JavaScript代码的速度并不高。通常的“倒计时到零”优化(for (i = length - 1; i >= 0; --i)而不是for (i = 0; i < length; ++i))这样简单的事情在实现中甚至都不可靠。因此,我倾向于坚持编写相当清晰的代码(因为我希望对任何必须维护它的人都很好,这通常是我),然后担心在何时何时进行优化。

也就是说,通过the Google article查看与his/her answer相关的tszming提醒我,在编写代码时,我倾向于记住一些性能问题。这是一个列表(一些来自那篇文章,一些不是):

  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对象的属性,它是一个宿主对象,因此与用于其他级别的匿名对象略有不同范围。但我希望你无论如何都已经避免了全局。

  8. 这是#6的一个例子。几个星期前我在一个与Prototype有关的问题中看到了这个:

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

    在Prototype中,$$做了一件昂贵的事情:它在DOM树中搜索匹配的元素(在这种情况下,是带有“foo”类的元素)。上面的代码是在每个循环上搜索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 :(得分:1)

答案 2 :(得分:1)

我认为这不是一个表演的事情,但除非你真的知道发生了什么,否则我必须避免这样做:

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

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

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