2

如果有一个重复激活的回调,例如以下...

Template.foo.rendered = function() {
    $(this.firstNode).droppable({
        // other arguments
        drop: function() {
            // some really long function that doesn't access anything in the closure
        }
    });
}

我应该将其优化为以下内容吗?

dropFunction = function() {
    // some really long function that doesn't access anything in the closure
} 

Template.foo.rendered = function() {
    $(this.firstNode).droppable({
        // other arguments
        drop: dropFunction
    });
}

在这种情况下,回调是一个 Meteor 构造,当它们被构造时,它在rendered带有模板的 DOM 节点上异步运行;foo可能有很多。是否有助于在全局闭包中的某处声明该函数,以节省 Javascript 引擎跟踪额外的本地闭包的麻烦,还是没关系?

4

2 回答 2

1

我不相信在现代浏览器中甚至会有差异。创建闭包对象时,V8 会确定您的函数使用哪些变量,如果您不使用变量,它将不会将其放入闭包对象中(我不久前在网上某处读到过,抱歉我找不到链接*见下文*)。我假设任何编译 JavaScript 的浏览器都会这样做。

将优化的是函数的创建。在第二个示例中,drop 函数与渲染函数同时创建,在第一个示例中,每次调用渲染函数时都会重新创建它。如果这是一个很长的 for 循环,可能值得优化。

我个人认为第一个例子更容易阅读和维护。正如我在对问题的评论中所说的那样,您(或将来编辑此代码的人)可能会意外地覆盖函数变量(在事件处理程序或其他东西中),并且您可能很难找到手上的错误。我建议用数字 1 说,或者将所有内容包装在一个自动执行的函数中,这样 dropFunction 的范围更小,被覆盖的机会也更小,如下所示:

(function () {
    var dropFunction = function() {
        // some really long function that doesn't access anything in the closure
    } 

    Template.foo.rendered = function() {
        $(this.firstNode).droppable({
            // other arguments
            drop: dropFunction
        });
    }
})();

编辑:我找到了链接,它实际上是在一篇关于 Meteor 中的闭包内存泄漏的博客文章中!

http://point.davidglasser.net/2013/06/27/surprising-javascript-memory-leak.html

这是我提到的部分:

JavaScript 实现(或至少当前的 Chrome)足够聪明,可以注意到 logIt 中没有使用 str,因此它没有放入 logIt 的词法环境中,一旦运行完成就可以对大字符串进行 GC。

于 2013-09-26T18:41:15.837 回答
0

我将首先说我对流星一无所知:/但如果我理解正确发生的事情,基本上:

Template.foo.rendered

被反复调用。发生这种情况时,您构造并对象 + 在其上定义一个新函数“drop”,该函数最终被调用。如果是这种情况,那么从性能角度来看,您最好在解析时定义一次 drop。但好处可能取决于调用渲染的频率。

至于为什么 - 我在这里发布了类似的内容:

循环中javascript中函数声明与函数表达式的性能

我认为@soktinpk 的回答我认为是一个很好的总结。

如果您查看上面链接中的 jsperf,它最初可能看起来并不直接适用,但如果我上面假设的陈述是真的,它实际上是 - 因为手头的问题归结为在运行时定义函数与解析时间,你是否在运行时一遍又一遍地定义这个函数。

如果您查看在运行时定义函数的循环与在解析时定义函数(或在解析时定义并提升)的循环的性能,解析时循环的运行速度明显更快。

我相信你的例子中流星所做的相当于可能是这样的 jsperf:http: //jsperf.com/how-expensive-is-defining-a-function-at-runtime2

我在这里所做的是创建了两个循环来模拟你的场景被一遍又一遍地调用。第一个调用创建对象和函数的函数,并将其传递给另一个函数进行调用。

第二个创建引用一个函数的对象并将其传递给另一个函数进行调用。性能差异看起来很显着(铬为 58%)。

于 2014-11-07T14:57:05.997 回答