为 RC.5 更新
使用 Angular 2,我们可以debounceTime()在表单控件的valueChangesobservable上使用 RxJS 操作符去抖动:
import {Component}   from '@angular/core';
import {FormControl} from '@angular/forms';
import {Observable}  from 'rxjs/Observable';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/throttleTime';
import 'rxjs/add/observable/fromEvent';
@Component({
  selector: 'my-app',
  template: `<input type=text [value]="firstName" [formControl]="firstNameControl">
    <br>{{firstName}}`
})
export class AppComponent {
  firstName        = 'Name';
  firstNameControl = new FormControl();
  formCtrlSub: Subscription;
  resizeSub:   Subscription;
  ngOnInit() {
    // debounce keystroke events
    this.formCtrlSub = this.firstNameControl.valueChanges
      .debounceTime(1000)
      .subscribe(newValue => this.firstName = newValue);
    // throttle resize events
    this.resizeSub = Observable.fromEvent(window, 'resize')
      .throttleTime(200)
      .subscribe(e => {
        console.log('resize event', e);
        this.firstName += '*';  // change something to show it worked
      });
  }
  ngDoCheck() { console.log('change detection'); }
  ngOnDestroy() {
    this.formCtrlSub.unsubscribe();
    this.resizeSub  .unsubscribe();
  }
} 
Plunker
上面的代码还包括一个如何限制窗口大小调整事件的示例,正如@albanx 在下面的评论中所问的那样。
虽然上面的代码可能是 Angular 的做法,但效率不高。每个击键和每个调整大小事件,即使它们被去抖动和限制,也会导致更改检测运行。换句话说,去抖动和限制不会影响更改检测运行的频率。(我发现Tobias Bosch的GitHub 评论证实了这一点。)您可以在运行 plunker 时看到这一点,并ngDoCheck()在您输入输入框或调整窗口大小时看到调用了多少次。(使用蓝色的“x”按钮在单独的窗口中运行 plunker 以查看调整大小事件。)
一种更有效的技术是从 Angular 的“区域”之外的事件中自己创建 RxJS Observables。这样,每次触发事件时都不会调用更改检测。然后,在您的订阅回调方法中,手动触发更改检测——即,您控制何时调用更改检测:
import {Component, NgZone, ChangeDetectorRef, ApplicationRef, 
        ViewChild, ElementRef} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/throttleTime';
import 'rxjs/add/observable/fromEvent';
@Component({
  selector: 'my-app',
  template: `<input #input type=text [value]="firstName">
    <br>{{firstName}}`
})
export class AppComponent {
  firstName = 'Name';
  keyupSub:  Subscription;
  resizeSub: Subscription;
  @ViewChild('input') inputElRef: ElementRef;
  constructor(private ngzone: NgZone, private cdref: ChangeDetectorRef,
    private appref: ApplicationRef) {}
  ngAfterViewInit() {
    this.ngzone.runOutsideAngular( () => {
      this.keyupSub = Observable.fromEvent(this.inputElRef.nativeElement, 'keyup')
        .debounceTime(1000)
        .subscribe(keyboardEvent => {
          this.firstName = keyboardEvent.target.value;
          this.cdref.detectChanges();
        });
      this.resizeSub = Observable.fromEvent(window, 'resize')
        .throttleTime(200)
        .subscribe(e => {
          console.log('resize event', e);
          this.firstName += '*';  // change something to show it worked
          this.cdref.detectChanges();
        });
    });
  }
  ngDoCheck() { console.log('cd'); }
  ngOnDestroy() {
    this.keyupSub .unsubscribe();
    this.resizeSub.unsubscribe();
  }
} 
Plunker
我使用ngAfterViewInit()代替ngOnInit()来确保inputElRef已定义。
detectChanges()将对该组件及其子组件运行更改检测。如果您更愿意从根组件运行更改检测(即,运行完整的更改检测检查),请ApplicationRef.tick()改用。(我ApplicationRef.tick()在 plunker 的评论中调用了 。)请注意,调用tick()将导致ngDoCheck()被调用。