为什么NgZone会解决这个问题?

时间:2017-07-05 19:17:16

标签: angular zone zonejs

我正在创建一个应用程序,用户可以通过他的Google帐户识别自己。在幕后,我正在使用gapi来处理登录。另一方面,存在称为“用户”的角度服务,其具有Observable,其在每次用户的状态(在线/离线)改变时向订户广播信息。然后,将所有内容粘合在一起,有一个按钮,当用户点击它时,会发生以下情况:

  • 创建一个promise,一旦gapi初始化就会解析。 (下面代码的第1行)
  • 当承诺解决后,Google登录将通过gapi执行。 (下面代码的第2行)
  • 当登录承诺解析时,向后端发出AJAX请求ID以验证Google令牌并返回诸如电子邮件,名称等信息并订阅此可观察对象。 (以下代码中以this.restService开头的行)
  • 当上面的observable发出我的Web服务返回的值时,我在我的“用户”服务中调用一个函数,该函数在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服务执行的持续时间有关。为了确保这一点,我在其中做了一个声明,在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语句,只是为了看看会发生什么,事实证明它没有......所以把所有内容都放在一个承诺中似乎解决了这个问题......但是,问题仍然存在......为什么第一个例子不起作用?

0 个答案:

没有答案