Debounce Angular ngDoCheck生命周期钩子

时间:2017-08-03 16:28:30

标签: angular

我一直在进行一项与Angular组件中处理状态相关的小实验。

假设我的计算成本很高,取决于其他几个。我可以编写一个函数updateVar()并在我知道可能影响它的每个事件上调用它,例如。通过订阅。但是当在超过5个不同的地方调用上述函数时,它感觉不是很干,也不健壮。

相反,如何去抖动DoCheck Angular生命周期钩子?

docheckSubject: Subject<any> = new Subject();
debounced: boolean = false;

constructor(private cd: ChangeDetectorRef) {}

ngOnInit() {
  this.docheckSubject.debounceTime(50).subscribe(
    () => this.ngDoCheckDebounced()
  );
}

ngDoCheck() {
  if (!this.debounced) {
    this.docheckSubject.next();
  } else {
    this.debounced = false;
  }
}

ngDoCheckDebounced() {
  this.debounced = true;
  this.updateVar();
  this.cd.detectChanges();  // needed to reflect update in DOM
}

这是plunker example

这种方法似乎在我的真实应用程序中运行良好,当然更多的ngDoCheck()正在发生,而Protractor测试也没有抱怨。但我无法摆脱做一个肮脏的不那么聪明的黑客的感觉。

问题:这会咬我吗?事实上,我是否真的需要它?

3 个答案:

答案 0 :(得分:1)

ngDoCheck经常被调用:

https://angular.io/guide/lifecycle-hooks#docheck

This hook is called with enormous frequency—after every change detection cycle no matter where the change occurred.

将此钩子用于Angular不知道的变量检测变量之外的其他任何东西都是一个坏主意。 (例如,输入对象更改其某个属性的值)。 Debouncing有点帮助,但你仍然经常执行那个逻辑,并且在你不再需要它之后会继续这样做(即debounced == false时)。

我认为您的解决方案可行,但我认为这种方法的开销远远低于替代方案。可能值得将更新逻辑作为Observable链的一部分,或将Observables传递给将该逻辑添加到链中的函数。

答案 1 :(得分:1)

经过几个月的生产没有问题(AFAICT),我最终删除它,因为它最终导致e2e(量角器)测试阻止,直到有人手动点击页面。显然不可持续。

我无法正确诊断此问题的原因,它可能源于我们代码中不相关部分的怪癖,但比抱歉更安全。

答案 2 :(得分:0)

你可以把变量放在一个getter中,只在重新计算时才重新计算吗?

这是一个简单的例子:

//our root app component
import {Component, NgModule, VERSION} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <div>x={{x}}</div>
      <div>y={{y}}</div>
      <button (click)="increment()">Increment</button>
      <div>Calculated Value={{calculatedValue}}</div>
    </div>
  `,
})
export class App {
  name:string;
  x: number = 0;
  y: number = 10;

  get calculatedValue(): number {
    return this.x * this.y;
  }

  constructor() {
    this.name = `Angular! v${VERSION.full}`
  }

  increment(): number {
    this.x++;
  }

}

相关的Plunker:https://plnkr.co/edit/QC7mkbsbjRRBjJOjWSHe?p=preview