代码之家  ›  专栏  ›  技术社区  ›  hvgotcodes

要避免的javascript构造?

  •  0
  • hvgotcodes  · 技术社区  · 14 年前

    我一直在写JS算法。它在铬中燃烧得很快,在FF中则缓慢。在chrome profiler中,我在一个方法中花费了10%,在ff中,相同的方法是执行时间的30%。是否有需要避免的JavaScript构造,因为它们在一个或另一个浏览器中的速度非常慢?

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

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

    只是做

    dosomething(y.x)
    

    例如。

    3 回复  |  直到 14 年前
        1
  •  5
  •   Community paulsm4    7 年前

    正如您所发现的,不同的实现中存在不同的问题。根据我的经验,除了做一些非常愚蠢的事情外,在目标浏览器上测试时遇到特定的性能问题之前/除非遇到特定的性能问题,否则无需担心如何将JavaScript代码优化为更快。像通常的“倒计时到零”优化这样简单的事情( for (i = length - 1; i >= 0; --i) 而不是 for (i = 0; i < length; ++i) )在不同的实现中甚至不可靠。因此,我倾向于坚持编写相当清楚的代码(因为我想对必须维护它的人友好,这通常是我自己),然后担心何时优化。

    也就是说,看看 the Google article 和他联系在一起的 his/her answer 提醒我,在最初编写代码时,有一些性能方面的事情我往往会记住。这是一个列表(有些来自那篇文章,有些不来自):

    1. 当您用大量片段构建一个长字符串时,如果您构建一个片段数组,然后使用 Array#join 方法创建最终字符串。如果我要构建一个大的HTML代码片段,我会经常这样做,我会把它添加到一个页面中。

    2. 这个 Crockford private instance variable pattern 虽然酷而有力,但价格昂贵。我倾向于避免它。

    3. with 价格昂贵,容易被误解。避开它。

    4. 当然,内存泄漏最终代价高昂。当您与DOM元素交互时,在浏览器上创建它们相当容易。有关更多详细信息,请参阅本文,但基本上,使用良好的库(如jquery、原型、闭包等)连接事件处理程序(因为这是一个特别容易出现的区域,库会提供帮助),并避免通过expando属性将dom元素引用存储在其他dom元素上(直接或间接)。

    5. 如果您正在浏览器中构建一个重要的动态内容显示, innerHTML 在大多数情况下比使用DOM方法快得多( createElement appendChild )这是因为有效地将HTML解析为其内部结构是 浏览器的功能 它们使用优化的编译代码,直接将代码写入内部数据结构,速度非常快。相反,如果您使用DOM方法构建一个重要的树,那么您使用的是一种解释性(通常)语言,它与一种抽象进行对话,而浏览器不必翻译来匹配其内部结构。我做的 a few experiments 一段时间前,两者之间的差异大约是一个数量级(有利于 内层HTML )当然,如果你正在建立一个大字符串来分配给 内层HTML ,请参见上面的提示-最好在数组中构建片段,然后使用 join .

    6. 缓存已知的缓慢操作的结果,但不要过度,并且只保留您需要的时间。记住保留样板客户的成本与再次查找样板客户的成本。

    7. 我反复听到有人说,从包含作用域访问var(当然,全局将是这方面的最终示例,但是您可以在其他作用域中使用闭包)比访问本地的慢,当然,这在纯解释的、非优化的实现中是有意义的,因为作用域链的方式定义。但我从未真正看到这是一个巨大的区别 在实践中 . ( 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树中搜索匹配的元素(在本例中,是具有类“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({/* ... */});
        }
    }
    

    …但是进一步(例如向后工作到零)是没有意义的,在一个浏览器上可能更快,在另一个浏览器上可能更慢。

        3
  •  1
  •   Pointy    14 年前

    我不认为这真的是一个性能方面的事情,但要避免一些事情,除非你 真的? 知道发生了什么事:

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

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

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