Angular:禁用整个类(服务或组件)的变更检测器 [英] Angular: Disable Change Detector for an entire class (service or component)

查看:27
本文介绍了Angular:禁用整个类(服务或组件)的变更检测器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果通常导致更改检测运行的事件(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 示例

如果你只想在某个类中禁用 setTimeoutsetInterval 你可以修补这些函数

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 示例

这篇关于Angular:禁用整个类(服务或组件)的变更检测器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆