角度:禁用整个类(服务或组件)的变更检测器 [英] Angular: Disable Change Detector for an entire class (service or component)
问题描述
如果通常导致更改检测运行的事件(setTimeout,setInterval,浏览器事件,ajax调用等)来自特定类(服务或组件),是否可以完全禁用Angular的更改检测器?
Is there a way to completely disable Angular's change detector if events that normally cause the change detection to run (setTimeout, setInterval, browser events, ajax calls etc..), are coming from a specific class (service or component)?
也就是说,当我发现在我的服务中注册的setInterval
导致每秒执行一次全局更改检测时,这对我来说似乎是完全错误的.
Namely, it seemed totally wrong to me when I found out that the setInterval
registered in my service causes the global change detection to run every second..
我知道我可以将代码包装在NgZone.runOutsideAngular
方法的回调中,但是我更喜欢可以在整个类中禁用更改检测器的解决方案,因为我在服务中还有其他代码块也不必要地运行检测.
I'm aware I can wrap my code inside the NgZone.runOutsideAngular
method's callback, but I'd prefer the solution where the change detector can be disabled for an entire class, as I have other chunks of code within the service that are needlessly running the detection too.
感谢您的帮助.
推荐答案
一种可能的解决方案可能是为您的服务使用以下@RunOutsideAngular
装饰器:
One possible solution might be the following @RunOutsideAngular
decorator for your service:
declare let Zone: any;
export function RunOutsideAngular(target: any) {
Object.getOwnPropertyNames(target.prototype)
.filter(p => typeof target.prototype[p] === 'function')
.forEach(p => {
let originalMethod = target.prototype[p];
target.prototype[p] = function (...args) {
let self = this;
Zone.root.run(() => originalMethod.apply(self, args));
}
});
let ctor: any = function (...args) {
let self = this;
return Zone.root.run(() => target.apply(self, args));
};
ctor.prototype = target.prototype;
return ctor;
}
Plunker Example
如果您只想在某个类中禁用setTimeout
和setInterval
,则可以修补这些功能
If you want to disable only setTimeout
and setInterval
within some class you can patch these functions
function patchTimers(timers: any[]) {
timers.forEach((timer) => {
let originalMethod = window[timer];
window[timer] = function (...args) {
let self = this;
if (Zone.current['__runOutsideAngular__'] === true && Zone.current.name === 'angular') {
Zone.root.run(() => originalMethod.apply(self, args));
} else {
originalMethod.apply(this, arguments);
}
};
})
}
patchTimers(['setTimeout', 'setInterval']);
并创建这样的装饰器
export function RunOutsideAngular(target: any) {
Object.getOwnPropertyNames(target.prototype)
.filter(p => typeof target.prototype[p] === 'function')
.forEach(p => {
let originalMethod = target.prototype[p];
target.prototype[p] = function (...args) {
Zone.current['__runOutsideAngular__'] = true;
originalMethod.apply(this, args);
delete Zone.current['__runOutsideAngular__'];
}
});
let ctor: any = function (...args) {
Zone.current['__runOutsideAngular__'] = true;
let instance = target.apply(this, args);
delete Zone.current['__runOutsideAngular__'];
return instance;
};
ctor.prototype = target.prototype;
return ctor;
}
然后您可以按以下方式使用它
Then you can use it as follows
@RunOutsideAngular
export class Service {
constructor() {
setInterval(() => {
console.log('ctor tick');
}, 1000);
}
run() {
setTimeout(() => {
console.log('tick');
}, 1000);
setInterval(() => {
console.log('tick interval');
}, 1000)
}
}
Plunker Example
这篇关于角度:禁用整个类(服务或组件)的变更检测器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!