我是jQuery的新手。我有点困惑是否好或可能导致内存泄漏?
以下是代码:在每个新值的某些日期过滤器上调用此方法
function preapreTooltip(chart) {
var tickLength = chart.xAxis[0].tickPositions.length,
ticks = chart.xAxis[0].ticks,
tickPositions = chart.xAxis[0].tickPositions;
for ( var iCntr = 0; iCntr < tickLength; iCntr++) {
var tickVal = tickPositions[iCntr];
//.label or .mark or both
(function(tickVal) { // Is this good practice to call function like this?
ticks[tickVal].label
.on('mouseover', function(event) { // Is this good practice to call function like this?
var label = '', labelCnt=0;
$(chart.series).each(function(nCntr, series) {
//business logic for each series
});
// calling method to show values in a popup
});
ticks[tickVal].label.on('mouseout', function(event) { // Is this good practice to call function like this?
try {
hideWrapper(); // hides popup
} catch (e) {
// do nothing
}
});
})(tickVal);
}
}
答案 0 :(得分:19)
虽然在编写大型纯JavaScript项目时需要避免浏览器特定问题,但在使用jQuery等库时,应该假设库的设计可以帮助您避免这些问题。但是,考虑到内存泄漏很难追踪,并且特定浏览器的每个不同版本的行为可能会有所不同 - 知道如何通常避免内存泄漏比特定内容要好得多:
element.onclick = function(){}
。你似乎相信这是调用一个会对泄漏产生影响的函数的方式,但它总是更有可能是那些可能导致问题的函数的内容。
每当使用事件侦听器时,尝试找到重用函数的方法,而不是每个元素创建一个。这可以通过使用event delegation (将事件捕获到祖先/父级并将反应委托给event.target
),或编写单个通用函数来处理相对方式的元素,通常相对于this
或$(this)
。
当需要创建许多事件处理程序时,通常最好将这些事件侦听器存储为命名函数,以便在完成后再次删除它们。这意味着避免使用匿名函数。但是,如果您知道只有您的代码处理DOM,您可以回退到使用$(elements).unbind('click')
删除使用jQuery应用于所选元素的所有点击处理程序(匿名或非匿名) 。但是,如果你确实使用后一种方法,那么使用jQuery的事件命名空间能力肯定会更好 - 所以你知道你只是删除了你的事件。即$(elements).unbind('click.my_app');
。这显然意味着您必须使用$(elements).bind('click.my_app', function(){...});
自动调用匿名函数
(function(){
/*
running an anonymous function this way will never cause a memory
leak because memory leaks (at least the ones we have control over)
require a variable reference getting caught in memory with the
JavaScript runtime still believing that the variable is in use,
when it isn't - meaning that it never gets garbage collected.
This construction has nothing to reference it, and so will be
forgotten the second it has been evaluated.
*/
})();
使用jQuery添加匿名事件监听器:
var really_large_variable = {/*Imagine lots of data here*/};
$(element).click(function(){
/*
Whilst I will admit not having investigated to see how jQuery
handles its event listeners onunload, I doubt if it is auto-
matically unbinding them. This is because for most code they
wont cause a problem, especially if only a few are in use. For
larger projects though it is a good idea to create some beforeunload
or unload handlers that delete data and unbind any event handling.
The reason for this is not to protect against the reference of the
function itself, but to make sure the references the function keeps
alive are removed. This is all down to how JS scope works, if you
have never read up on JavaScript scope... I suggest you do so.
As an example however, this anonymous function has access to the
`really_large_variable` above - and will prevent any garbage collection
system from deleting the data contained in `really_large_variable`
even if this function or any other code never makes use of it.
When the page unloads you would hope that the browser would be able
to know to clear the memory involved, but you can't be 100% certain
it will *(especially the likes of IE6/7)* - so it is always best
to either make sure you set the contents of `really_large_variable` to null
or make sure you remove your references to your closures/event listeners.
*/
});
关于我的解释,我专注于何时不再需要页面并且用户正在导航。然而,在今天的ajaxed内容和高度动态的界面世界中,上述内容变得更加重要;不断创建和破坏元素的GUI。
如果您正在创建一个动态javascript应用程序,我不能强调在不再需要代码时使用.tearDown
或.deconstruct
方法构建构造函数的重要性。这些应该逐步执行大型自定义对象构造并使其内容无效,以及删除已动态创建且不再使用的事件侦听器和元素。在替换元素的内容之前,您还应该使用jQuery的empty
方法 - 这可以用他们的话来更好地解释:
为了避免内存泄漏,jQuery会在删除元素本身之前从子元素中删除其他构造(如数据和事件处理程序)。
如果要在不破坏数据或事件处理程序的情况下删除元素(以便以后可以重新添加),请改用.detach()。
使用tearDown方法进行编码不仅会迫使您更加整洁(即确保将相关的代码,事件和元素保持在一起),这通常意味着您需要在更多代码中构建代码模块化时尚;对于未来的应用程序,可读性以及可能在以后接管您的项目的任何其他人来说,这显然要好得多。
答案 1 :(得分:1)
以下是使用Chrome或Safari检测内存泄漏的优秀文章:http://javascript.crockford.com/memory/leak.html
使用Developer Tools面板并不是众所周知的功能。
有趣且非常有用!
编辑
这不是好的联系(但仍然有用)。这是一个:http://gent.ilcore.com/2011/08/finding-memory-leaks.html