我正在创建一个应用程序,用户可以通过他的Google帐户识别自己。在幕后,我正在使用gapi来处理登录。另一方面,存在称为“用户”的角度服务,其具有Observable
,其在每次用户的状态(在线/离线)改变时向订户广播信息。然后,将所有内容粘合在一起,有一个按钮,当用户点击它时,会发生以下情况:
this.restService
开头的行)以下是代码:
this.ensureApiIsLoaded().then(() => {
this.auth.signIn().then((user) => {
let profile = user.getBasicProfile();
this.restService
.post("/api/security/authenticate", <IAuthenticationPayload>{ type: AuthenticationType.Google, token: user.getAuthResponse().id_token })
.subscribe((data: IUserData) => {
this.userService.set("data.name", "data.email", "data.picture", AuthenticationType.Google);
});
});
});
问题在于代码有时会起作用,有时却不起作用。经过一番调查后,我发现它与我的Web服务执行的持续时间有关。为了确保这一点,我在其中做了一个声明,在2秒内暂停执行请求。在这种情况下,我的代码总是失败。但是,“失败”是什么意思?
在页面的某个地方,我有一个订阅了用户服务observable的组件:
this.userService.getStatus().subscribe(status => {
console.log(status);
this.canPostComment = (status == UserStatus.Online);
});
当Web服务执行得非常快时,我会看到console.log
,然后更新canPostComment
属性,我的视图也是如此,所以没有问题。但是,当Web服务需要更长时间时,我仍然会看到console.log
具有正确的值,但视图未更新...
怀疑它与Angular变化检测有关,我以这种方式使用zone:
this.ensureApiIsLoaded().then(() => {
this.auth.signIn().then((user) => {
let profile = user.getBasicProfile();
this.zoneService.run(() => {
this.restService
.post("/api/security/authenticate", <IAuthenticationPayload>{ type: AuthenticationType.Google, token: user.getAuthResponse().id_token })
.subscribe((data: IUserData) => {
this.userService.set("data.name", "data.email", "data.picture", AuthenticationType.Google);
});
});
});
});
然后它工作......所以我读到了区域,我了解到它用于警告角度它必须运行变化检测(或类似的东西......),但我也读到了常见的功能,如setTimeout
或AJAX调用已经被“区域”修补了,所以我不知道它是如何解决我的问题的,我不知道为什么我有这个问题。为什么Angular看不到canPostComment
已经改变了?
由于我的代码有点复杂,所以很难搞清楚,这就是我复制/粘贴大部分相关代码的原因。
修改
在我提出问题之后,我不得不修改我的代码,因为我需要知道整个登录过程何时完成。实际上,当用户点击登录按钮时,其标题变为“登录...”,一旦整个过程完成,它就会消失。我本来可以订阅userService.getStatus
观察者,但我决定接受能够做到的承诺:
this.googleAuthenticationService.login.then(() => { ... });
所以我用这种方式更新了代码:
return new Promise((resolve, reject) => {
this.ensureApiIsLoaded().then(() => {
this.auth.signIn().then((user) => {
let profile = user.getBasicProfile();
this.zoneService.run(() => {
this.restService
.post("/api/security/authenticate", <IAuthenticationPayload>{ type: AuthenticationType.Google, token: user.getAuthResponse().id_token })
.subscribe((data: IUserData) => {
this.userService.set(data.name, data.email, data.picture, AuthenticationType.Google);
resolve(true)
},
error => reject(false));
});
});
});
});
出于好奇,我试图删除this.zoneService.run
语句,只是为了看看会发生什么,事实证明它没有......所以把所有内容都放在一个承诺中似乎解决了这个问题......但是,问题仍然存在......为什么第一个例子不起作用?