龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > web编程 > Javascript编程 >

编写高性能JavaScript(译)(7)

时间:2014-08-14 12:18来源:网络整理 作者:网络 点击:
分享到:
“Profile”选项卡展示了代码性能信息。 一个很好的分析介绍,阅读Zack Grossbart的 JavaScript Profiling With The Chrome Developer Tools 。 提示:在理想情况下,若想确

profiling2

“Profile”选项卡展示了代码性能信息。

一个很好的分析介绍,阅读Zack Grossbart的 JavaScript Profiling With The Chrome Developer Tools

提示:在理想情况下,若想确保你的分析并未受到已安装的应用程序或扩展的任何影响,可以使用--user-data-dir <empty_directory>标志来启动Chrome。在大多数情况下,这种方法优化测试应该是足够的,但也需要你更多的时间。这是V8标志能有所帮助的。

避免内存泄漏——3快照技术

在谷歌内部,Chrome开发者工具被Gmail等团队大量使用,用来帮助发现和排除内存泄漏。

devtools

Chrome开发者工具中的内存统计

内存统计出我们团队所关心的私有内存使用、JavaScript堆的大小、DOM节点数量、存储清理、事件监听计数器和垃圾收集器正要回收的东西。推荐阅读Loreena Lee的“3快照”技术。该技术的要点是,在你的应用程序中记录一些行为,强制垃圾回收,检查DOM节点的数量有没有恢复到预期的基线,然后分析三个堆的快照来确定是否有内存泄漏。

单页面应用的内存管理

单页面应用程序(例如AngularJS,Backbone,Ember)的内存管理是非常重要的,它们几乎永远不会刷新页面。这意味着内存泄漏可能相当明显。移动终端上的单页面应用充满了陷阱,因为设备的内存有限,并在长期运行Email客户端或社交网络等应用程序。能力愈大责任愈重。

有很多办法解决这个问题。在Backbone中,确保使用dispose()来处理旧视图和引用(目前在Backbone(Edge)中可用)。这个函数是最近加上的,移除添加到视图“event”对象中的处理函数,以及通过传给view的第三个参数(回调上下文)的model或collection的事件监听器。dispose()也会被视图的remove()调用,处理当元素被移除时的主要清理工作。Ember 等其他的库当检测到元素被移除时,会清理监听器以避免内存泄漏。

Derick Bailey的一些明智的建议:

与其了解事件与引用是如何工作的,不如遵循的标准规则来管理JavaScript中的内存。如果你想加载数据到的一个存满用户对象的Backbone集合中,你要清空这个集合使它不再占用内存,那必须这个集合的所有引用以及集合内对象的引用。一旦清楚了所用的引用,资源就会被回收。这就是标准的JavaScript垃圾回收规则。

在文章中,Derick涵盖了许多使用Backbone.js时的常见内存缺陷,以及如何解决这些问题。

Felix Geisendörfer的在Node中调试内存泄漏的教程也值得一读,尤其是当它形成了更广泛SPA堆栈的一部分。

减少回流(REFLOWS)

当浏览器重新渲染文档中的元素时需要 重新计算它们的位置和几何形状,我们称之为回流。回流会阻塞用户在浏览器中的操作,因此理解提升回流时间是非常有帮助的。

reflow

回流时间图表

你应该批量地触发回流或重绘,但是要节制地使用这些方法。尽量不处理DOM也很重要。可以使用DocumentFragment,一个轻量级的文档对象。你可以把它作为一种方法来提取文档树的一部分,或创建一个新的文档“片段”。与其不断地添加DOM节点,不如使用文档片段后只执行一次DOM插入操作,以避免过多的回流。

例如,我们写一个函数给一个元素添加20个div。如果只是简单地每次append一个div到元素中,这会触发20次回流。

function addDivs(element) {
 var div;
 for (var i = 0; i < 20; i ++) {
 div = document.createElement('div');
 div.innerHTML = 'Heya!';
 element.appendChild(div);
 }
}

要解决这个问题,可以使用DocumentFragment来代替,我们可以每次添加一个新的div到里面。完成后将DocumentFragment添加到DOM中只会触发一次回流。

function addDivs(element) {
 var div; 
 // Creates a new empty DocumentFragment.
 var fragment = document.createDocumentFragment();
 for (var i = 0; i < 20; i ++) {
 div = document.createElement('a');
 div.innerHTML = 'Heya!';
 fragment.appendChild(div);
 }
 element.appendChild(fragment);
}

可以参阅 Make the Web FasterJavaScript Memory OptimizationFinding Memory Leaks

JS内存泄漏探测器

精彩图集

赞助商链接