Angular 2 + OnPush:更改检测不适用于pouchdb回调

时间:2017-01-22 12:50:47

标签: angular pouchdb angular2-changedetection

我在离子应用中将Angular 2与PouchDB结合使用作为数据库。出于性能原因,我选择在任何地方使用OnPush + Async管道。我现在偶然发现,如果pouchdb事件导致更改,它不会反映在模板中:

我有一个数据库类,只计算数据库更改的数量:

@Injectable()
export class Database {
  foo$ = new BehaviorSubject(0);

  (...)

  sync(url, options) {
    this.pouchdb.sync(url, options)
      .on('change', this.changed.bind(this));
    this.foo$.subscribe(count => console.debug('the count is', count));
  }

  changed() {
    this.foo$.next(this.foo$.value + 1);
  }
}

在模板中我使用异步管道来显示数字:

{{ db.foo$|async }}

但是这不起作用:即使存在数据库更改(控制台输出显示数据库更改的数量),数字仍然卡住。但是,如果我点击某些内容,数字会突然跳到正确的值。

我发现这令人惊讶,因为我认为异步管道通过订阅一个observable工作,一旦这个observable发出一些东西,模板内的值就会更新。显然,这在这里不起作用,因为我知道observable发出的东西(正如我从控制台输出中看到的那样),但是更改没有反映在模板中。

你知道导致这种行为的原因/如何改变它吗?

其他信息

为了确保它是pouchDB<>的组合。导致麻烦的Angular,我使用了这个函数

sync(url, options) {
  window.setInterval(this.changed.bind(this), 1000);
}

导致模板内的值每秒都正确更新。

修改

我发现这个虚拟代码

window.setInterval(() => {}, 1000);

修复了问题,因为它可能每秒触发更改检测。我不明白的是,为什么异步管道没有检测到变化?

1 个答案:

答案 0 :(得分:4)

TL; DR:代码在角度区域外运行,因此变化不会被角度处理,直到下一个更改检测周期。

使用chrome dev工具,在调用更改时放置断点。请注意,如果您在pouchdb调用和setInterval之间看到调用堆栈的差异。具体来说,setInterval可能有一些区域绑定周围的调用,而pouchdb调用不是。如果是这样,你可以:

  • 查看初始化的顺序 - see this SO - 或者如果pouchdb可以通过猴子方式修补以调用角区内的承诺。
  • 在数据库构造函数中注入private zone: NgZone并在changed()中使用this.zone.run(() => this.foo$.next(this.foo$.value + 1));以确保进入角度区域。

如果所有其他方法都失败,请登录并手动标记更改检测(using ChangeDetectionRef)。但是,由于这必须在使用db的组件中完成,因此它是一个绝对可怕的抽象泄漏。

享受。让我们知道你找到了什么。