Angular NgZone是如何解决这个问题的?
我正在创建一个应用程序,用户可以通过他的谷歌帐户识别自己。在幕后,我使用gapi来处理登录。另一方面,有一种称为“用户”的角度服务,它具有一个Angular NgZone是如何解决这个问题的?,angular,zone,zonejs,Angular,Zone,Zonejs,我正在创建一个应用程序,用户可以通过他的谷歌帐户识别自己。在幕后,我使用gapi来处理登录。另一方面,有一种称为“用户”的角度服务,它具有一个可观察的,每当用户的状态(在线/离线)改变时,它都向订户广播信息。然后,要将所有内容粘合在一起,有一个按钮,当用户单击它时,会发生以下情况: 创建一个承诺,该承诺在gapi初始化后解析。(下面代码的第1行) 当承诺解决时,Google登录将通过gapi执行。(下面代码的第二行) 当登录承诺得到解决时,会向后端发出一个AJAX请求id,以验证Google令
可观察的
,每当用户的状态(在线/离线)改变时,它都向订户广播信息。然后,要将所有内容粘合在一起,有一个按钮,当用户单击它时,会发生以下情况:
- 创建一个承诺,该承诺在gapi初始化后解析。(下面代码的第1行)
- 当承诺解决时,Google登录将通过gapi执行。(下面代码的第二行)
- 当登录承诺得到解决时,会向后端发出一个AJAX请求id,以验证Google令牌,并返回电子邮件、名称等信息,并订阅此可观察内容。(以下代码中以
开头的行)this.restService
- 当上面的observable发出web服务返回的值时,我在“user”服务中调用一个函数,该函数在observable上发出用户状态的值(它广播用户现在已通过身份验证的事实)李>
- 然后,所有订户都会收到此信息并知道用户已登录
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服务执行得非常快时,我会看到console.log
,然后更新canPostComment
属性,我的视图也会更新,因此不会出现问题。但是,当web服务花费的时间稍长时,我仍然可以看到console.log
具有正确的值,但是视图没有更新
我怀疑它与角度变化检测有关,所以我使用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);
});
});
});
});
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.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);
});
});
});
});
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));
});
});
});
});
返回新承诺((解决、拒绝)=>{
此.ensureApiIsLoaded()。然后(()=>{
this.auth.sign().then((用户)=>{
让profile=user.getBasicProfile();
this.zoneService.run(()=>{
这是我们的服务
.post(“/api/security/authenticate”,{type:AuthenticationType.Google,token:user.getAuthResponse().id_token})
.订阅((数据:IUserData)=>{
this.userService.set(data.name、data.email、data.picture、AuthenticationType.Google);
解析(真)
},
错误=>拒绝(错误));
});
});
});
});
出于好奇,我试图删除
this.zoneService.run
语句,只是想看看会发生什么,结果发现它在没有。。。所以把一切都放在一个承诺里似乎可以解决问题。。。然而,问题仍然存在。。。为什么第一个示例不起作用?我没有完整的答案,但这篇博文对区域进行了很好的解释:。Angular钩住Zone.js,在每个VM回合之后(即,在任何单个任务以及所有后续微任务完成之后)运行更改检测循环。该区域由角度控制。如果您在更改检测周期内进行更改(即,ApplicationRef.tick()
在堆栈中),则您尚未开始新任务,更改检测将不会重新运行。你可以检查一下这篇文章来了解发生了什么。呵呵,这就是我在作品中提到的那篇文章。但我会再看一遍,也许我遗漏了什么。而且,很有可能它没有在Angular的范围内运行儿童承诺。我不知道为什么不这样做,但以防万一你可以考虑链接你的承诺而不是创建子承诺:<代码> .EnSuxRiPiSoLoDeD()。然后(()=这个。Auth.Suin())。然后((用户)= {{…});能否在控制台.log(状态)之后添加以下内容代码>语句console.log('Zone is:',Zone.current.name)代码>?嗨,“区域”对象来自哪里?我尝试注入NgZone 1,但其中没有“当前”属性。然而,通过尝试这样做,我注意到,如果我把所有事情都写进一个承诺中,我就不再需要这个区域了。事实上,我更新了代码,以了解整个过程何时完成,因此我在其周围添加了新承诺…
,现在,当我删除区域。运行部分时,无论我的web服务花费多少时间,它都能工作。。。我会更新OP。