AngularJS 带有 $http 的指令会造成内存泄漏 - .resolve 似乎不起作用?
AngularJS directive with $http creates memory leak - .resolve doesn't seem to work?
我似乎遇到了问题,但我认为我看不到解决方案,也许有人可以提供帮助...我有一个 AngularJS 指令,它使 $http
请求 returns HTML 并且当有内容时我将它注入我的视图 - 我知道这不是很好并且 HTML 的返回应该替换为 JSON 和使用模板,但我无法控制 $http 请求返回的内容。该指令需要一些 arguments/attributes 才能获得正确的内容,并且一切似乎都有效。在我看来,直接通常在 7 个位置,一个在我的导航中,我使用 ng-include 添加到我的索引中,在我的页脚中三次,我使用 ng-include
添加到我的 index.html 然后是指令出现在我拥有的 ng-view
标签中,该标签在每个视图中可以出现 0 到 3 次。这是我的 HTML
中的指令
<div data-cms-inject data-page-name="homePageContent" data-slot-name="slot1"></div>
这是 JS...
.directive('cmsInject', ['$rootScope', '$q', '$http', function ($rootScope, $q, $http) {
'use strict';
return {
restrict: 'A',
link: function (scope, element, attrs) {
var canceller = $q.defer(),
cmsPromise = $http({
url : 'url/to/feed',
timeout: canceller.promise,
method: 'POST',
data: [{
pageName: attrs.pageName,
slotName: attrs.slotName
}]
});
cmsPromise.success(function(data) {
var resp = data[0];
if(resp.replace(/\s{1,}/,'').replace(/\r?\n|\r/g,'') !== 'null') {
element.html(resp);
}
console.log('new request success');
$rootScope.$broadcast('cmsLoaded');
}).error(function(data) {
console.log('new request error', data);
}) ;
$rootScope.$on('$locationChangeStart', function () {
console.log('$locationChangeStart');
canceller.resolve('locationChange');
});
}
};
}])
现在这似乎工作正常,但当我在我的应用程序的视图之间快速导航时,我注意到应用程序似乎变慢,然后浏览器崩溃,因此我们有内存泄漏。起初我认为这是由于挂起的 $http 调用引起的,但是当我尝试使用超时和“$locationChangeStart”事件解决这些问题时,问题仍然存在。然后我尝试写入控制台以查看会发生什么...这是我的输出...
这是当我加载应用程序时,我们有 7 个指令实例,3 个在 ng-view 内,4 个在 ng-includes 外
7 new request success
然后我切换到一个没有指令的新视图
7 $locationChangeStart
然后我导航回原来的视图
7 $locationChangeStart
3 new request success
我再次切换到没有指令的新视图
10 $locationChangeStart
我导航回原来的视图
10 $locationChangeStart
3 new request success
我再次切换到没有指令的新视图
13 $locationChangeStart
终于回到原来的样子
13 $locationChangeStart
3 new request success
这里有些奇怪,因为调用 $locationChangeStart 事件的次数增加了,比指令在页面中出现的次数还多,ng-include + ng-view 谁能看出我在这里做错了什么,我猜 memory/DOM 中遗留了一些指令?
事件处理程序数量的增加可以解释为:
$rootScope.$on('$locationChangeStart'
您将事件处理程序附加到 $rootScope
,当然,当指令的生命周期结束时,它不会消失。事件处理程序应附加到 scope
。
您的指令在 DOM 和 js 对象之间创建了循环引用。尽量避免将事件绑定到 rootScope 并在指令 link 函数中使用 $http 等服务。更好的解决方案是将此逻辑放在模块 运行 函数中。
类似的东西:
.run(['$rootScope', 'myService', function($rootScope, myService){
$rootScope.$on('$locationChangeStart', function () {
myService.doSomethng().then(function(data){
var resp = data[0];
if(resp.replace(/\s{1,}/,'').replace(/\r?\n|\r/g,'') !== 'null') {
$rootScope.$broadcast('cmsLoaded', data);
}
});
});
}])
.directive('cmsInject', ['$rootScope', '$q', '$http', function ($rootScope, $q, $http) {
'use strict';
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$on('cmsLoaded', function(e, args) {
element.html(args);
})
}
}
}])
将您的 http 调用移至某个服务并在您的指令中使用该服务。监听指令的“$destory”事件,如果可以的话做一些清理工作。
我似乎遇到了问题,但我认为我看不到解决方案,也许有人可以提供帮助...我有一个 AngularJS 指令,它使 $http
请求 returns HTML 并且当有内容时我将它注入我的视图 - 我知道这不是很好并且 HTML 的返回应该替换为 JSON 和使用模板,但我无法控制 $http 请求返回的内容。该指令需要一些 arguments/attributes 才能获得正确的内容,并且一切似乎都有效。在我看来,直接通常在 7 个位置,一个在我的导航中,我使用 ng-include 添加到我的索引中,在我的页脚中三次,我使用 ng-include
添加到我的 index.html 然后是指令出现在我拥有的 ng-view
标签中,该标签在每个视图中可以出现 0 到 3 次。这是我的 HTML
<div data-cms-inject data-page-name="homePageContent" data-slot-name="slot1"></div>
这是 JS...
.directive('cmsInject', ['$rootScope', '$q', '$http', function ($rootScope, $q, $http) {
'use strict';
return {
restrict: 'A',
link: function (scope, element, attrs) {
var canceller = $q.defer(),
cmsPromise = $http({
url : 'url/to/feed',
timeout: canceller.promise,
method: 'POST',
data: [{
pageName: attrs.pageName,
slotName: attrs.slotName
}]
});
cmsPromise.success(function(data) {
var resp = data[0];
if(resp.replace(/\s{1,}/,'').replace(/\r?\n|\r/g,'') !== 'null') {
element.html(resp);
}
console.log('new request success');
$rootScope.$broadcast('cmsLoaded');
}).error(function(data) {
console.log('new request error', data);
}) ;
$rootScope.$on('$locationChangeStart', function () {
console.log('$locationChangeStart');
canceller.resolve('locationChange');
});
}
};
}])
现在这似乎工作正常,但当我在我的应用程序的视图之间快速导航时,我注意到应用程序似乎变慢,然后浏览器崩溃,因此我们有内存泄漏。起初我认为这是由于挂起的 $http 调用引起的,但是当我尝试使用超时和“$locationChangeStart”事件解决这些问题时,问题仍然存在。然后我尝试写入控制台以查看会发生什么...这是我的输出...
这是当我加载应用程序时,我们有 7 个指令实例,3 个在 ng-view 内,4 个在 ng-includes 外
7 new request success
然后我切换到一个没有指令的新视图
7 $locationChangeStart
然后我导航回原来的视图
7 $locationChangeStart
3 new request success
我再次切换到没有指令的新视图
10 $locationChangeStart
我导航回原来的视图
10 $locationChangeStart
3 new request success
我再次切换到没有指令的新视图
13 $locationChangeStart
终于回到原来的样子
13 $locationChangeStart
3 new request success
这里有些奇怪,因为调用 $locationChangeStart 事件的次数增加了,比指令在页面中出现的次数还多,ng-include + ng-view 谁能看出我在这里做错了什么,我猜 memory/DOM 中遗留了一些指令?
事件处理程序数量的增加可以解释为:
$rootScope.$on('$locationChangeStart'
您将事件处理程序附加到 $rootScope
,当然,当指令的生命周期结束时,它不会消失。事件处理程序应附加到 scope
。
您的指令在 DOM 和 js 对象之间创建了循环引用。尽量避免将事件绑定到 rootScope 并在指令 link 函数中使用 $http 等服务。更好的解决方案是将此逻辑放在模块 运行 函数中。
类似的东西:
.run(['$rootScope', 'myService', function($rootScope, myService){
$rootScope.$on('$locationChangeStart', function () {
myService.doSomethng().then(function(data){
var resp = data[0];
if(resp.replace(/\s{1,}/,'').replace(/\r?\n|\r/g,'') !== 'null') {
$rootScope.$broadcast('cmsLoaded', data);
}
});
});
}])
.directive('cmsInject', ['$rootScope', '$q', '$http', function ($rootScope, $q, $http) {
'use strict';
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$on('cmsLoaded', function(e, args) {
element.html(args);
})
}
}
}])
将您的 http 调用移至某个服务并在您的指令中使用该服务。监听指令的“$destory”事件,如果可以的话做一些清理工作。