Angular何时以及如何释放DOM以防止内存泄漏?

时间:2014-08-25 00:45:43

标签: angularjs dom memory compilation

Angular新手在这里。我有这个自定义指令,它包装表行以显示标记的信息。当我单击行中的“编辑”按钮时,指令模板将被更改并允许用户更新标签名称,当我单击“应用”按钮时,行将更改回更新的标签名称,或者如果我点击“取消编辑”按钮,该行也将被更改回来,没有任何更新。所以editTag和cancelEditTag事件函数如下所示:

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开发工具分析此应用时,我意识到通过点击“编辑”和“取消编辑”按钮打开和关闭“编辑模式”,内存使用量不断攀升(每次约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>&nbsp;&nbsp;<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>&nbsp;&nbsp;<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;
});

任何帮助将不胜感激,提前谢谢!

1 个答案:

答案 0 :(得分:0)

所以,我已经找到了一种不动态编译指令模板的方法,从而避免了内存使用量的增加。那就是添加一个名为&#39; isEditMode&#39;的布尔标志。将在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>&nbsp;&nbsp;<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>&nbsp;&nbsp;<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;

});

这样,指令模板不会被重复编辑用于编辑/非编辑模式,而只会根据&#39; ng-if =&#34; isEditMode&#34;&#39;显示不同的DOM。它解决了我的问题。然而,我仍然想知道是否有一种方法可以消除动态指令模板编译的内存泄漏。任何想法都将不胜感激。