- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我使用 ng-repeat 创建元素(有些是 SVG 标签,有些是简单的 HTML)。在数据模型发生变化时——一个在新数据到达时重置的对象——总会有元素作为分离的 DOM 元素留下。他们是这样举行的:
元素是 data_user 的一部分,它似乎是 jquery 的一部分。此问题发生在多个更改数据的地方。似乎观察者是问题所在,因为他们一直在引用自己的表情。
元素被创建,例如像这样:
.directive('svgGraphic', ['$compile', function ($compile) {
return {
restrict: 'E',
replace: false,
link: function (scope, element, attrs) {
var svgData = scope.model.getAttribute("svgGraphic");
var svgDomElement = $(svgData.svg);
scope.layers = svgData.layers;
svgDomElement.append('<svg-layer ng-repeat="layer in layers"></svg-layer>');
element.append($compile(svgDomElement)(scope));
scope.$on("$destroy", function() {
scope.$$watchers = null;
scope.$$listeners = null;
})
}
};
}])
解决方法是手动删除观察者和听众,如上所示 - 我认为这不是好的解决方案!
当来自服务器的新数据到达时,它是这样设置的:
$scope.model = model;
$scope.$digest();
只替换模型数据有问题吗?
是否知道 angular 不会删除旧元素上的监听器是如何发生的?当 ng-repeat 接收到新数据并重建所有元素时,Angular 应该删除所有观察者。
最佳答案
我发现了同样的问题。我创建了一个 Watcher 类,然后使用探查器我可以计算 Watcher 实例。当我浏览应用程序时,我看到实例继续增加,一些实例由 data_user 缓存保留:(。
我还修复了 childScopes 观察器的删除问题,并向范围添加了一些元数据,例如 childScope 列表。
这是我更改的 Angular 代码(只有我更改的功能)。我希望这可以帮助您找到错误,我仍在与它作斗争:)
function $RootScopeProvider() {
this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
function($injector, $exceptionHandler, $parse, $browser) {
var watcherCount = 0;
function Watcher(listener, initWatchVal, get, watchExp, objectEquality, scope) {
this.fn = isFunction(listener) ? listener : noop;
this.last = initWatchVal;
this.get = get;
this.exp = watchExp;
this.eq = !!objectEquality;
this.scope = scope;
this.id = watcherCount++;
}
Watcher.prototype = {
constructor: Watcher
}
function Scope() {
this.$id = nextUid();
this.$$phase = this.$parent = this.$$watchers =
this.$$nextSibling = this.$$prevSibling =
this.$$childHead = this.$$childTail = null;
this.$root = this;
this.$$destroyed = false;
this.$$listeners = {};
this.$$listenerCount = {};
this.$$isolateBindings = null;
this.childsScopes = [];
}
Scope.prototype = {
constructor: Scope,
$new: function(isolate, parent) {
var child;
parent = parent || this;
if (isolate) {
child = new Scope();
child.$root = this.$root;
} else {
// Only create a child scope class if somebody asks for one,
// but cache it to allow the VM to optimize lookups.
if (!this.$$ChildScope) {
this.$$ChildScope = function ChildScope() {
this.$$watchers = this.$$nextSibling =
this.$$childHead = this.$$childTail = null;
this.$$listeners = {};
this.$$listenerCount = {};
this.$id = nextUid();
this.$$ChildScope = null;
};
this.$$ChildScope.prototype = this;
}
child = new this.$$ChildScope();
}
//window.scopes = window.scopes || {};
//window.scopes[child.$id] = child;
this.childsScopes.push(child);
child.$parent = parent;
child.$$prevSibling = parent.$$childTail;
if (parent.$$childHead) {
parent.$$childTail.$$nextSibling = child;
parent.$$childTail = child;
} else {
parent.$$childHead = parent.$$childTail = child;
}
// When the new scope is not isolated or we inherit from `this`, and
// the parent scope is destroyed, the property `$$destroyed` is inherited
// prototypically. In all other cases, this property needs to be set
// when the parent scope is destroyed.
// The listener needs to be added after the parent is set
if (isolate || parent != this) child.$on('$destroy', destroyChild);
return child;
function destroyChild() {
child.$$destroyed = true;
child.$$watchers = null;
child.$$listeners = {};
//child.$parent = null;
child.$$nextSibling = null;
child.$$childHead = null;
child.$$childTail = null;
child.$$prevSibling = null;
child.$$listenerCount = {};
if (child.$parent) {
var index = child.$parent.childsScopes.indexOf(child);
child.$parent.childsScopes.splice(index, 1);
}
console.log("Destroying childScope " + child.$id);
}
}
$destroy: function() {
// we can't destroy the root scope or a scope that has been already destroyed
if (this.$$destroyed) return;
var parent = this.$parent;
console.log('Destroying Scope '+ this.$id);
//delete window.scopes[this.$id];
this.$broadcast('$destroy');
this.$$destroyed = true;
if (this === $rootScope) return;
for (var eventName in this.$$listenerCount) {
decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
}
// sever all the references to parent scopes (after this cleanup, the current scope should
// not be retained by any of our references and should be eligible for garbage collection)
if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
// Disable listeners, watchers and apply/digest methods
this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
this.$on = this.$watch = this.$watchGroup = function() { return noop; };
this.$$listeners = {};
// All of the code below is bogus code that works around V8's memory leak via optimized code
// and inline caches.
//
// see:
// - https://code.google.com/p/v8/issues/detail?id=2073#c26
// - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
// - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
this.$$childTail = this.$root = this.$$watchers = null;
}
}];
}
关于javascript - 内存泄漏 : Remaining elements in cache and data_user in AngularJs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25015947/
我使用 ng-repeat 创建元素(有些是 SVG 标签,有些是简单的 HTML)。在数据模型发生变化时——一个在新数据到达时重置的对象——总会有元素作为分离的 DOM 元素留下。他们是这样举行的:
我是一名优秀的程序员,十分优秀!