Angularjs 何时以及如何释放DOM以防止内存泄漏?
我是个有棱角的新手。我有一个自定义指令,它包装一个表行以显示标记的信息。当我单击行中的“编辑”按钮时,指令模板将被更改,并允许用户更新标记名;当我单击“应用”按钮时,该行将使用更新的标记名更改回原来的行;或者,如果我单击“取消编辑”按钮,该行也将更改回原来的行,而不进行任何更新。因此editTag和cancelEditTag事件函数如下所示:Angularjs 何时以及如何释放DOM以防止内存泄漏?,angularjs,dom,memory,compilation,Angularjs,Dom,Memory,Compilation,我是个有棱角的新手。我有一个自定义指令,它包装一个表行以显示标记的信息。当我单击行中的“编辑”按钮时,指令模板将被更改,并允许用户更新标记名;当我单击“应用”按钮时,该行将使用更新的标记名更改回原来的行;或者,如果我单击“取消编辑”按钮,该行也将更改回原来的行,而不进行任何更新。因此editTag和cancelEditTag事件函数如下所示: scope.editTag = function() { scope.originalTagName = scope.tag.name;
scope.editTag = function() {
scope.originalTagName = scope.tag.name;
element.html(getTemplate(true));
$compile(element.contents())(scope);
};
scope.cancelEditTag = function() {
scope.tag.name = scope.originalTagName;
element.html(getTemplate(false));
$compile(element.contents())(scope);
scope.tagSubmitError = false;
scope.errorMessage = '';
};
然而,当使用Chrome dev工具评测这个应用程序时,我意识到,当通过单击“编辑”和“取消编辑”按钮打开和关闭“编辑模式”时,每次内存使用量都会不断攀升约0.1-0.2mb,我想我这里有内存泄漏,我猜$compile之后,旧DOM还没有被释放?如果是,我应该如何处理?如果不是这样的话,麻烦制造者还会是什么?或者根本不是内存泄漏?对于完整上下文,以下是我的指令的完整代码:
app.directive('taginfo', function($compile ,$http) {
var directive = {};
directive.tagSubmitError = true;
directive.errorMessage = '';
directive.originalTagName = '';
directive.restrict = 'A';
directive.scope = {
tag : '=',
selectedTagIds : '=selected',
};
function getTemplate(isEditing) {
if (isEditing) {
return '<th><input type="checkbox" ng-click="selectTag()" ng-checked="selectedTagIds.indexOf(tag.id) != -1"></th>' +
'<th>' +
'<input type="text" class="form-control" ng-model="tag.name" placeholder="请输入标签名称">' +
'<div class="alert alert-danger" style="margin-top: 5px; " ng-show="tagSubmitError" ng-bind="errorMessage"></div>' +
'</th>' +
'<th><span class="label num-post"><%tag.num_items%></span></th>' +
'<th><button class="action-submit-edit" ng-click="submitEditTag()"><i class="icon-ok-2"></i></button> <button class="action-cancel-edit" ng-click="cancelEditTag()"><i class="icon-ban"></i></button></th>';
} else {
return '<th><input type="checkbox" ng-click="selectTag()" ng-checked="selectedTagIds.indexOf(tag.id) != -1"></th>' +
'<th><%tag.name%></th>' +
'<th><span class="label num-post"><%tag.num_items%></span></th>' +
'<th><button class="action-edit" ng-click="editTag()"><i class="icon-pencil"></i></button> <button class="action-delete"><i class="icon-bin"></i></button></th>';
}
}
directive.template = getTemplate(false);
directive.link = function(scope, element, attributes) {
scope.selectTag = function() {
var index = scope.selectedTagIds.indexOf(scope.tag.id);
if (index == -1) {
scope.selectedTagIds.push(scope.tag.id);
} else {
scope.selectedTagIds.splice(index, 1);
}
};
scope.submitEditTag = function() {
if (scope.tag.name.length === 0) {
scope.tagSubmitError = true;
scope.errorMessage = '请输入标签名称';
} else {
$http.post('/admin/posts/edit_tag', {'tagId': scope.tag.id, 'tagName': scope.tag.name}).success(function(data, status, headers, config) {
if (data.statusCode == 'error') {
scope.tagSubmitError = true;
scope.errorMessage = data.errorMessage;
} else if (data.statusCode == 'success') {
scope.tag.name = data.tag_name;
scope.tagSubmitError = false;
scope.errorMessage = '';
element.html(getTemplate(false));
$compile(element.contents())(scope);
}
});
}
};
scope.editTag = function() {
scope.originalTagName = scope.tag.name;
element.html(getTemplate(true));
$compile(element.contents())(scope);
};
scope.cancelEditTag = function() {
scope.tag.name = scope.originalTagName;
element.html(getTemplate(false));
$compile(element.contents())(scope);
scope.tagSubmitError = false;
scope.errorMessage = '';
};
};
return directive;
});
任何帮助都将不胜感激,提前感谢 所以,我找到了一种不动态编译指令模板的方法,从而避免了内存使用量的增加。即添加一个名为“isEditMode”的布尔标志,该标志将在ng if中使用,以决定显示哪个DOM,源代码如下:
app.directive('taginfo', function($http, $animate, listService) {
var directive = {};
directive.editTagSubmitError = false;
directive.errorMessage = '';
directive.originalTagName = '';
directive.restrict = 'A';
directive.isEditMode = false;
directive.scope = {
tag : '=',
pagination : '=',
data : '='
};
directive.template = '<th><input type="checkbox" ng-click="selectTag()" ng-checked="data.selectedIds.indexOf(tag.id) != -1"></th>' +
'<th ng-if="isEditMode">' +
'<input type="text" class="form-control" ng-model="tag.name" placeholder="请输入标签名称">' +
'<div class="alert alert-danger" style="margin-top: 5px; " ng-show="editTagSubmitError" ng-bind="errorMessage"></div>' +
'</th>' +
'<th ng-if="!isEditMode"><%tag.name%></th>' +
'<th><span class="label num-posts"><%tag.num_items%></span></th>' +
'<th ng-if="isEditMode"><button class="action-submit-edit" ng-click="submitEditTag()"><i class="icon-ok-2"></i></button> <button class="action-cancel-edit" ng-click="cancelEditTag()"><i class="icon-ban"></i></button></th>' +
'<th ng-if="!isEditMode"><button class="action-edit" ng-click="editTag()"><i class="icon-pencil"></i></button> <button class="action-delete" ng-click="deleteTag()"><i class="icon-bin"></i></button></th>';
directive.link = function(scope, element, attributes) {
scope.selectTag = function() {
listService.selectEntry(scope.tag, scope.data);
};
scope.submitEditTag = function() {
if (!scope.tag.name) {
scope.editTagSubmitError = true;
scope.errorMessage = '请输入标签名称';
} else {
bootbox.confirm('是否确定修改标签名称为' + scope.tag.name +'?', function(result) {
if (result === true) {
$http.post('/admin/posts/edit_tag', {'tagId': scope.tag.id, 'tagName': scope.tag.name}).success(function(response, status, headers, config) {
if (response.statusCode == 'error') {
scope.editTagSubmitError = true;
scope.errorMessage = response.errorMessage;
} else if (response.statusCode == 'success') {
scope.isEditMode = false;
scope.tag.name = response.tag_name;
scope.editTagSubmitError = false;
scope.errorMessage = '';
$animate.removeClass(element, 'editing');
}
});
}
});
}
};
scope.editTag = function() {
scope.isEditMode = true;
scope.originalTagName = scope.tag.name;
if (!element.hasClass('editing')) {
element.addClass('editing');
}
};
scope.cancelEditTag = function() {
scope.isEditMode = false;
scope.tag.name = scope.originalTagName;
scope.editTagSubmitError = false;
scope.errorMessage = '';
};
scope.deleteTag = function() {
listService.deleteEntry(scope.tag, scope.tag.name, scope.data, '/admin/posts/delete_tag', scope.pagination, 'tag');
};
};
return directive;
})
这样,指令模板将不会被反复编译为编辑/非编辑模式,而只显示基于“ng if=isEditMode”的不同DOM。它解决了我的问题。但我仍然想知道是否有一种方法可以消除动态指令模板编译的内存泄漏。如果您有任何想法,我们将不胜感激。您能安装一个plunkr或JSFIDLE吗?它位于JSFIDLE上:只需多次单击“编辑标记”和“取消编辑”,您就会看到内存使用量不断增加。