字符串连接操作会对 Internet Explorer 6 和 7 的垃圾收集带来很大的影响。 尽管这个问题在 Internet Explorer 8 里面得到解决 -- 字符串连接在 IE8 和其它非 IE 浏览器(如 Chrome)中稍微更有效率一点 -- 如果你的用户中有很大一部分在使用 Internet Explorer 6 或 7, 你就需要非常注意你构建字符串的方式了。
有如下示例代码:
var veryLongMessage =
'This is a long string that due to our strict line length limit of' +
maxCharsPerLine +
' characters per line must be wrapped. ' +
percentWhoDislike +
'% of engineers dislike this rule. The line length limit is for ' +
' style purposes, but we don't want it to have a performance impact.' +
' So the question is how should we do the wrapping?';
比起用连接的方式, 尝试使用 join():
var veryLongMessage =
['This is a long string that due to our strict line length limit of',
maxCharsPerLine,
' characters per line must be wrapped. ',
percentWhoDislike,
'% of engineers dislike this rule. The line length limit is for ',
' style purposes, but we don't want it to have a performance impact.',
' So the question is how should we do the wrapping?'
].join();
相似的, 用连接的方式在条件语句和循环中构建字符串是很低效的。 错误的方式:
var fibonacciStr = '前 20 个斐波那契数 ';
for (var i = 0; i < 20; i++) {
fibonacciStr += i + ' = ' + fibonacci(i) + '
';
}
正确的方法:
var strBuilder = ['前 20 个斐波那契数:'];
for (var i = 0; i < 20; i++) {
strBuilder.push(i, ' = ', fibonacci(i));
}
var fibonacciStr = strBuilder.join('');
var strBuilder = [];
for (var i = 0; i < menuItems.length; i++) {
strBuilder.push(this.buildMenuItemHtml_(menuItems));
}
var menuHtml = strBuilder.join();
不如用:
var strBuilder = [];
for (var i = 0; i < menuItems.length; i++) {
this.buildMenuItem_(menuItems, strBuilder);
}
var menuHtml = strBuilder.join();
内存泄漏对 Web 应用而言是个很普遍的问题, 它会带来严重的性能问题。 当浏览器的内存使用上升时, 你的 Web 应用, 连同用户系统的其他部分, 都会变慢。 Web 应用最常见的内存泄漏原因是: 在 JavaScript 脚本引擎和浏览器 DOM 的 C++ 对象实现间的循环引用(例如, 在 JavaScript 脚本引擎和 Internet Explorer 的 COM 基础架构间, 或者 JavaScript 引擎和 Firefox 的 XPCOM 基础架构间)。
下面是避免内存泄漏的一些经验法则:
使用一个事件系统来附加事件处理函数
最常见的循环引用模式 [ DOM 元素 --》 事件处理函数 --》 闭包作用域 --》 DOM ] 在 这篇 MSDN 的 Blog 文章中讨论过了。 为避免这个问题, 可以使用一个经过严格测试的事件系统来附件事件处理函数, 例如 Google doctype, Dojo, or JQuery.
另外, 在 IE 中使用内联(inline)的事件处理函数会导致另外一类泄漏。 这不是通常的循环引用泄漏, 而是内存中临时匿名脚本对象的泄漏。 详情请查看 理解和解决 IE 泄漏模式(Understanding and Solving Internet Explorer Leak Patterns) 的 “DOM 插入顺序泄漏模型(DOM Insertion Order Leak Model)” 一节, 另外在 JavaScript Kit 教程 中还有一个例子。
避免使用扩展(expando)属性
扩展属性是附加到 DOM 元素上的任意 JavaScript 属性, 也是循环引用的常见原因。 你能够在使用扩展属性时不导致内存泄漏, 但是很容易不小心就引入一个泄漏。 这个泄漏的模式是 [ DOM 元素 --》 扩展属性 --》 中间对象 --》 DOM 元素 ]。 最好的方法就是避免使用它们。 如果你要使用它们, 就只使用简单的值类型。 如果你要非简单的类型, 那么在不再需要扩展属性时将它设为空(null)。 参见 理解和解决 IE 泄漏模式(Understanding and Solving Internet Explorer Leak Patterns) 中的 “循环引用(Circular References)” 一节.