单页应用程序 - 大型DOM - 慢速

时间:2013-09-20 01:32:35

标签: javascript html performance dom

我正在开发一个单页面应用程序,它使用jqWidgets库中的许多小部件(主要是网格和标签),这些小部件都是在页面加载时加载的。它已经变得非常大了我在使用之后开始注意到了(我强调使用因为它在开放任何时间后都没有开始滞后,但具体来说,在打开和关闭之后我的页面上有一堆标签,每个标签包含通过Ajax加载的多个网格,每个网格都有多个事件监听器绑定到每个网站几分钟,UI变得非常慢,有时无响应,当页面刷新时,一切顺利几分钟然后回到滞后。我还在测试localhost。我最初的反应是DOM有太多元素(每个网格创建数百个div!我有很多div)所以与ID绑定的事件监听器必须搜索太多元素并变慢。如果是这种情况,那么修复起来就不会太难,我的假设可能是罪魁祸首还是我害怕更糟糕的事情?

UPDATE:这里是内存时间线和堆快照的捕获。在内存时间线上没有与网站的互动,两个大的增加是页面刷新,中间锯齿部分只是让我的网站闲置。

enter image description here

enter image description here

3 个答案:

答案 0 :(得分:2)

没有看到任何代码示例,它听起来并不太糟糕。

如果你有很多jQuery选择器尝试尽可能具体。特别是如果你在很多时候选择了很多项目。

例如,如果您有一堆类“abc”,请尝试在之前指定 - 例如它们只在表格单元格中找到?他们只在段落标签中找到?您使选择器越具体,就像指定选择器一样:

$('.class')

然后它将在整个DOM中搜索匹配.class的任何内容,但是,如果您按如下方式指定它:$('p .class')那么它将只搜索该类的所有段落标记。

其他性能杀手正在连接事件,然后永远不会删除它们。如果您有任何代码可以删除附加了事件处理程序的元素,那么最佳做法是在删除元素时删除事件处理程序。否则你将开始堆积孤儿事件。

如果您正在进行大型单页应用程序,请查看像骨干(http://backbonejs.org/)或角度(http://angularjs.org/)这样的库,看看这是否可以帮助您 - 它们可以缓解许多这些问题使用普通jQuery的人将会运行。

最后,这篇文章(http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/)非常擅长概述您可以编写快速,高效的JavaScript以及如何避免常见的性能陷阱。

希望这有帮助。

答案 1 :(得分:2)

听起来好像你某处有内存泄漏。您是否正在使用未正确控制的递归,或者您是否有可以提前结束的循环,但是当您在循环自然结束之前找到您正在寻找的内容时,您无法突破它们。你在用这样的东西:

document.getElementById(POS.CurrentTableName + '-Menus').getElementsByTagName('td');

返回的节点列表很大,你最后只使用了一小部分。这些电话很贵。

也可能是您对建筑的选择。每个网格的数百个div在人类大脑的逻辑上听起来并不可控。你是否专门用id来解决每个div,或者它们只是你正在使用的lib的一个工件并且正在混乱DOM?您是否在使用它时检查了DOM本身,看看您是否在错误地在腹地添加元素并且使用您不使用的垃圾使DOM混乱,导致DOM在您使用应用程序时不断增长。您是否多次向元素添加事件处理程序而不是一次?

为了进行比较,我也有一个单页应用程序(谷歌 - Chrome应用程序 - 多币种餐厅销售点),其中有1,500到20,000个事件处理程序注册,在node.js服务器上调用sqlite后端。我主要使用纯JS,而且除了50行之外,所有HTML都是用JS编写的。我将所有事件处理程序直接绑定到负责该事件的最低级别元素。一些元素有多个处理程序(点击,更改,keydown,模糊等)。

该应用程序以眨眼速度运行,并且无论多长时间都保持快速。 DOM相当大,我经常销毁并重新创建它的大部分(餐厅表被清除并重新创建以供下次会议使用),包括每桌最多可添加1,500个事件处理程序。点击CLEAR按钮并用新表刷新屏幕几乎是不可察觉的,不可否认的是在高端处理器上。我的开发环境是Fedora 19 Linux。

答案 2 :(得分:1)

无法看到您的代码,有点难以准确说出来。

如果UI在开始变得迟钝之前需要一点点,那么听起来你的JavaScript中某处可能存在内存泄漏。当使用大量闭包以及嵌套函数和变量引用时,这很快就会发生,而不会在完成它们时进行清理。

此外,绑定到许多元素的事件可能会大量消耗浏览器资源。如果可能,尝试使用事件委派来降低侦听事件的元素数量。例如: $('table')。on('click','td',myEventHandler);

小心确保事件绑定仅发生一次,以避免多次无意中触发操作。

祝你好运!