Angular 角度2+;OnPush:更改检测在数据库回调上不起作用
我在一个离子应用程序中使用Angular 2,并结合PockDB作为数据库。出于性能原因,我选择在任何地方使用OnPush+异步管道。现在,我偶然发现了这样一个事实,即如果PockDB事件导致了更改,那么它不会反映在模板中: 我有一个数据库类,它只计算数据库更改的数量:Angular 角度2+;OnPush:更改检测在数据库回调上不起作用,angular,pouchdb,angular2-changedetection,Angular,Pouchdb,Angular2 Changedetection,我在一个离子应用程序中使用Angular 2,并结合PockDB作为数据库。出于性能原因,我选择在任何地方使用OnPush+异步管道。现在,我偶然发现了这样一个事实,即如果PockDB事件导致了更改,那么它不会反映在模板中: 我有一个数据库类,它只计算数据库更改的数量: @Injectable() export class Database { foo$ = new BehaviorSubject(0); (...) sync(url, options) { this.p
@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 }}
但这不起作用:即使有数据库更改,数字也会被卡住(控制台输出显示数据库更改的数量)。但是,如果我点击某个东西,数字会突然跳到正确的值
我觉得这很惊人,因为我认为异步管道是通过订阅一个可观察对象来工作的,一旦这个可观察对象发出某种信息,模板中的值就会更新。显然,这在这里不起作用,因为我知道可观察的对象发出了一些东西(正如我从控制台输出中看到的),但是更改没有反映在模板中
你知道是什么导致这种行为/如何改变它吗
其他信息
为了确保这两个函数的组合导致了问题,我使用了这个函数
sync(url, options) {
window.setInterval(this.changed.bind(this), 1000);
}
这会导致模板中的值每秒正确更新一次
编辑
我发现这个伪代码
window.setInterval(() => {}, 1000);
修复了该问题,因为它可能每秒触发一次更改检测。我不明白的是,为什么异步管道没有检测到更改;DR:代码在angular区域之外运行,所以angular在下一个更改检测周期之前不会处理更改 使用chromedev工具,在调用changed时放置一个断点。请注意,如果您看到PockDB调用和setInterval之间的调用堆栈存在差异。具体来说,setInterval可能在调用周围有一些区域操纵,而PockDB调用没有。如果是,你可以:
- 查看初始化的顺序——或者是否可以对PockDB进行猴子补丁,以在angular zone内调用承诺
- 在数据库构造函数中注入
,并使用private zone:NgZone
this.zone.run(()=>this.foo$.next(this.foo$.value+1))代码>内部更改(),以确保进入角度区域
享受。让我们知道你发现了什么。在我看来,肯定还有更多。我将删除ChangeDetectionStrategy.OnPush,以确保这确实是问题的一部分。您确认了吗?直觉:您正在查看数据库的两个实例。模板中使用的与调用.sync的模板不同。谢谢您的回答!你是对的,责任不在推送,ChangeDetectionStrategy.Default也一样。但是,我完全确定没有两个不同的数据库实例。我注意到另一件事:如果我执行这个伪代码,一切都正常:window.setInterval(()=>{},1000);据我所知,这似乎确实是一个变化检测问题,setInterval每秒触发一次变化检测。但我不知道为什么AsiNC管道没有检测到它的变化……如果AsiNC管道不调用变化检测,我会认为它是一个bug。code>setInverval()可能与
setTimeout()
或ApplicationRef.tick()
相同,这会导致应用程序范围内的更改检测谢谢,zone.run()是一种解决方法。一旦我有更多的时间,我会详细研究这个问题,并让你知道我发现了什么